Skip to content

Commit 3b67466

Browse files
Bill LeoutsakosBill Leoutsakos
authored andcommitted
fix(oracle-hcm): correct privacy fixture assertion and apply CI formatting
1 parent 241ddfd commit 3b67466

17 files changed

Lines changed: 1018 additions & 439 deletions

‎apps/sim/blocks/blocks/oracle_fusion_hcm.ts‎

Lines changed: 118 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -301,7 +301,10 @@ export const OracleFusionHcmBlock: BlockConfig = {
301301
{ label: 'List performance documents', id: 'list_performance_documents' },
302302
{ label: 'Get performance document', id: 'get_performance_document' },
303303
{ label: 'List performance document roles', id: 'list_performance_document_roles' },
304-
{ label: 'List performance document participants', id: 'list_performance_document_participants' },
304+
{
305+
label: 'List performance document participants',
306+
id: 'list_performance_document_participants',
307+
},
305308
{ label: 'List performance document tasks', id: 'list_performance_document_tasks' },
306309
{ label: 'List talent profiles', id: 'list_talent_profiles' },
307310
{ label: 'Get talent profile', id: 'get_talent_profile' },
@@ -372,8 +375,43 @@ export const OracleFusionHcmBlock: BlockConfig = {
372375
selectorKey: 'oracle_fusion_hcm.workers',
373376
dependsOn: ['credential'],
374377
mode: 'basic',
375-
condition: { field: 'operation', value: [...PERSON_OPERATIONS, 'get_absence', ...['list_payroll_element_definitions', 'list_element_entries', 'create_element_entry', 'list_person_process_results', 'list_performance_goals', 'list_development_goals', 'list_performance_documents', 'list_talent_profiles', 'list_payroll_input_values', 'get_performance_document', 'list_performance_document_roles', 'list_performance_document_participants', 'list_performance_document_tasks', 'get_talent_profile', 'list_talent_profile_sections', 'list_talent_profile_skills', 'list_talent_profile_certifications', 'list_salaries', 'create_salary', 'get_salary', 'correct_salary', 'list_salary_components', 'create_time_entry', 'update_time_entry']] },
376-
required: { field: 'operation', value: [...PERSON_OPERATIONS, ...['create_element_entry', 'list_development_goals']] },
378+
condition: {
379+
field: 'operation',
380+
value: [
381+
...PERSON_OPERATIONS,
382+
'get_absence',
383+
...[
384+
'list_payroll_element_definitions',
385+
'list_element_entries',
386+
'create_element_entry',
387+
'list_person_process_results',
388+
'list_performance_goals',
389+
'list_development_goals',
390+
'list_performance_documents',
391+
'list_talent_profiles',
392+
'list_payroll_input_values',
393+
'get_performance_document',
394+
'list_performance_document_roles',
395+
'list_performance_document_participants',
396+
'list_performance_document_tasks',
397+
'get_talent_profile',
398+
'list_talent_profile_sections',
399+
'list_talent_profile_skills',
400+
'list_talent_profile_certifications',
401+
'list_salaries',
402+
'create_salary',
403+
'get_salary',
404+
'correct_salary',
405+
'list_salary_components',
406+
'create_time_entry',
407+
'update_time_entry',
408+
],
409+
],
410+
},
411+
required: {
412+
field: 'operation',
413+
value: [...PERSON_OPERATIONS, ...['create_element_entry', 'list_development_goals']],
414+
},
377415
placeholder: 'Select a worker',
378416
},
379417
{
@@ -382,8 +420,43 @@ export const OracleFusionHcmBlock: BlockConfig = {
382420
type: 'short-input',
383421
canonicalParamId: 'personId',
384422
mode: 'advanced',
385-
condition: { field: 'operation', value: [...PERSON_OPERATIONS, 'get_absence', ...['list_payroll_element_definitions', 'list_element_entries', 'create_element_entry', 'list_person_process_results', 'list_performance_goals', 'list_development_goals', 'list_performance_documents', 'list_talent_profiles', 'list_payroll_input_values', 'get_performance_document', 'list_performance_document_roles', 'list_performance_document_participants', 'list_performance_document_tasks', 'get_talent_profile', 'list_talent_profile_sections', 'list_talent_profile_skills', 'list_talent_profile_certifications', 'list_salaries', 'create_salary', 'get_salary', 'correct_salary', 'list_salary_components', 'create_time_entry', 'update_time_entry']] },
386-
required: { field: 'operation', value: [...PERSON_OPERATIONS, ...['create_element_entry', 'list_development_goals']] },
423+
condition: {
424+
field: 'operation',
425+
value: [
426+
...PERSON_OPERATIONS,
427+
'get_absence',
428+
...[
429+
'list_payroll_element_definitions',
430+
'list_element_entries',
431+
'create_element_entry',
432+
'list_person_process_results',
433+
'list_performance_goals',
434+
'list_development_goals',
435+
'list_performance_documents',
436+
'list_talent_profiles',
437+
'list_payroll_input_values',
438+
'get_performance_document',
439+
'list_performance_document_roles',
440+
'list_performance_document_participants',
441+
'list_performance_document_tasks',
442+
'get_talent_profile',
443+
'list_talent_profile_sections',
444+
'list_talent_profile_skills',
445+
'list_talent_profile_certifications',
446+
'list_salaries',
447+
'create_salary',
448+
'get_salary',
449+
'correct_salary',
450+
'list_salary_components',
451+
'create_time_entry',
452+
'update_time_entry',
453+
],
454+
],
455+
},
456+
required: {
457+
field: 'operation',
458+
value: [...PERSON_OPERATIONS, ...['create_element_entry', 'list_development_goals']],
459+
},
387460
placeholder: 'Enter person ID',
388461
},
389462
{
@@ -395,8 +468,26 @@ export const OracleFusionHcmBlock: BlockConfig = {
395468
selectorKey: 'oracle_fusion_hcm.assignments',
396469
dependsOn: ['oauthCredential', 'personId'],
397470
mode: 'basic',
398-
condition: { field: 'operation', value: [...ASSIGNMENT_OPERATIONS, ...['create_element_entry', 'list_salaries', 'create_salary', 'get_salary', 'correct_salary', 'list_salary_components', 'create_time_entry', 'update_time_entry']] },
399-
required: { field: 'operation', value: [...ASSIGNMENT_OPERATIONS, ...['list_salaries', 'create_salary']] },
471+
condition: {
472+
field: 'operation',
473+
value: [
474+
...ASSIGNMENT_OPERATIONS,
475+
...[
476+
'create_element_entry',
477+
'list_salaries',
478+
'create_salary',
479+
'get_salary',
480+
'correct_salary',
481+
'list_salary_components',
482+
'create_time_entry',
483+
'update_time_entry',
484+
],
485+
],
486+
},
487+
required: {
488+
field: 'operation',
489+
value: [...ASSIGNMENT_OPERATIONS, ...['list_salaries', 'create_salary']],
490+
},
400491
placeholder: 'Select an assignment',
401492
},
402493
{
@@ -405,8 +496,26 @@ export const OracleFusionHcmBlock: BlockConfig = {
405496
type: 'short-input',
406497
canonicalParamId: 'assignmentId',
407498
mode: 'advanced',
408-
condition: { field: 'operation', value: [...ASSIGNMENT_OPERATIONS, ...['create_element_entry', 'list_salaries', 'create_salary', 'get_salary', 'correct_salary', 'list_salary_components', 'create_time_entry', 'update_time_entry']] },
409-
required: { field: 'operation', value: [...ASSIGNMENT_OPERATIONS, ...['list_salaries', 'create_salary']] },
499+
condition: {
500+
field: 'operation',
501+
value: [
502+
...ASSIGNMENT_OPERATIONS,
503+
...[
504+
'create_element_entry',
505+
'list_salaries',
506+
'create_salary',
507+
'get_salary',
508+
'correct_salary',
509+
'list_salary_components',
510+
'create_time_entry',
511+
'update_time_entry',
512+
],
513+
],
514+
},
515+
required: {
516+
field: 'operation',
517+
value: [...ASSIGNMENT_OPERATIONS, ...['list_salaries', 'create_salary']],
518+
},
410519
placeholder: 'Enter assignment ID',
411520
},
412521
{

‎apps/sim/lib/internal/oracle-fusion-hcm/execute-tool.test.ts‎

Lines changed: 23 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -83,20 +83,39 @@ function invokeHcmTool(overrides: Partial<InternalToolOperationCall>) {
8383

8484
describe('Oracle Fusion HCM tool dispatch', () => {
8585
it('marks ambiguous mutation failures non-retryable without exposing provider details', async () => {
86-
mocks.createSalary.mockRejectedValueOnce(new OracleFusionProviderError('Oracle Fusion HCM request timed out', 504))
86+
mocks.createSalary.mockRejectedValueOnce(
87+
new OracleFusionProviderError('Oracle Fusion HCM request timed out', 504)
88+
)
8789
const response = await invokeHcmTool({
8890
toolId: 'oracle_fusion_hcm_create_salary',
89-
input: { ...auth, assignmentId: '1', salaryBasisId: '2', salaryAmount: 1200, dateFrom: '2026-01-01', dateTo: '4712-12-31' },
91+
input: {
92+
...auth,
93+
assignmentId: '1',
94+
salaryBasisId: '2',
95+
salaryAmount: 1200,
96+
dateFrom: '2026-01-01',
97+
dateTo: '4712-12-31',
98+
},
9099
})
91100
expect(response.status).toBe(504)
92-
expect(await response.json()).toEqual({ success: false, error: 'Oracle Fusion HCM request timed out', retryable: false })
101+
expect(await response.json()).toEqual({
102+
success: false,
103+
error: 'Oracle Fusion HCM request timed out',
104+
retryable: false,
105+
})
93106
expect(mocks.createSalary).toHaveBeenCalledOnce()
94107
})
95108

96109
it('rejects a time update missing its version before dispatch', async () => {
97110
const response = await invokeHcmTool({
98111
toolId: 'oracle_fusion_hcm_update_time_entry',
99-
input: { ...auth, personNumber: '0007', timeRecordId: '2', measure: 8, referenceDate: '2026-01-01' },
112+
input: {
113+
...auth,
114+
personNumber: '0007',
115+
timeRecordId: '2',
116+
measure: 8,
117+
referenceDate: '2026-01-01',
118+
},
100119
})
101120
expect(response.status).toBe(400)
102121
expect(mocks.updateTimeEntry).not.toHaveBeenCalled()

‎apps/sim/lib/internal/oracle-fusion-hcm/execute-tool.ts‎

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -30,10 +30,17 @@ async function executeOperation<S extends z.ZodType>(
3030
} catch (error) {
3131
signal?.throwIfAborted()
3232
if (error instanceof OracleFusionProviderError) {
33-
return Response.json({ success: false, error: error.message, ...(mutation ? { retryable: false } : {}) }, { status: error.status })
33+
return Response.json(
34+
{ success: false, error: error.message, ...(mutation ? { retryable: false } : {}) },
35+
{ status: error.status }
36+
)
3437
}
3538
return Response.json(
36-
{ success: false, error: 'Oracle Fusion HCM request failed', ...(mutation ? { retryable: false } : {}) },
39+
{
40+
success: false,
41+
error: 'Oracle Fusion HCM request failed',
42+
...(mutation ? { retryable: false } : {}),
43+
},
3744
{ status: 500 }
3845
)
3946
}

‎apps/sim/lib/internal/oracle-fusion-hcm/operations.test.ts‎

Lines changed: 103 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -703,48 +703,130 @@ describe('Oracle Fusion HCM payroll, compensation, talent, and time', () => {
703703
}
704704

705705
it('reads historical payroll relationships without current worker-directory membership', async () => {
706-
mocks.requestOracleFusionJson.mockResolvedValueOnce(collection([{ PayrollRelationshipId: '9007199254740993', PersonNumber: '0007', EffectiveStartDate: '2001-01-01' }]))
707-
const result = await operations.executeOracleFusionHcmListPayrollRelationships({ ...auth, personNumber: '0007', effectiveDate: '2001-01-01' })
706+
mocks.requestOracleFusionJson.mockResolvedValueOnce(
707+
collection([
708+
{
709+
PayrollRelationshipId: '9007199254740993',
710+
PersonNumber: '0007',
711+
EffectiveStartDate: '2001-01-01',
712+
},
713+
])
714+
)
715+
const result = await operations.executeOracleFusionHcmListPayrollRelationships({
716+
...auth,
717+
personNumber: '0007',
718+
effectiveDate: '2001-01-01',
719+
})
708720
expect(mocks.requestOracleFusionJson).toHaveBeenCalledOnce()
709-
expect(lastRequest()).toMatchObject({ address: { family: 'hcm', relativePath: 'payrollRelationships' }, query: { q: "PersonNumber='0007'", effectiveDate: '2001-01-01', limit: 20, offset: 0 } })
721+
expect(lastRequest()).toMatchObject({
722+
address: { family: 'hcm', relativePath: 'payrollRelationships' },
723+
query: { q: "PersonNumber='0007'", effectiveDate: '2001-01-01', limit: 20, offset: 0 },
724+
})
710725
expect(result.output.payrollRelationships[0].payrollRelationshipId).toBe('9007199254740993')
711726
})
712727

713728
it('keeps payroll assignment identity distinct from HR assignment identity and bounds child pages', async () => {
714729
mocks.requestOracleFusionJson
715-
.mockResolvedValueOnce(discovery('payrollRelationships', 'PayrollRelationshipId', '1', 'relationship%20key'))
716-
.mockResolvedValueOnce(collection([{ RelationshipGroupId: '9007199254740993', AssignmentId: '9007199254740995', AssignmentNumber: 'E7', TimeCardRequired: 'Y' }], { limit: 10, offset: 30, hasMore: true }))
717-
const result = await operations.executeOracleFusionHcmListPayrollAssignments({ ...auth, payrollRelationshipId: '1', effectiveDate: '2020-01-01', limit: 10, offset: 30 })
718-
expect(lastRequest()).toMatchObject({ address: { relativePath: 'payrollRelationships/relationship%20key/child/payrollAssignments' }, query: { limit: 10, offset: 30, effectiveDate: '2020-01-01' } })
719-
expect(result.output.payrollAssignments[0]).toMatchObject({ payrollAssignmentId: '9007199254740993', assignmentId: '9007199254740995', timeCardRequired: 'Y' })
730+
.mockResolvedValueOnce(
731+
discovery('payrollRelationships', 'PayrollRelationshipId', '1', 'relationship%20key')
732+
)
733+
.mockResolvedValueOnce(
734+
collection(
735+
[
736+
{
737+
RelationshipGroupId: '9007199254740993',
738+
AssignmentId: '9007199254740995',
739+
AssignmentNumber: 'E7',
740+
TimeCardRequired: 'Y',
741+
},
742+
],
743+
{ limit: 10, offset: 30, hasMore: true }
744+
)
745+
)
746+
const result = await operations.executeOracleFusionHcmListPayrollAssignments({
747+
...auth,
748+
payrollRelationshipId: '1',
749+
effectiveDate: '2020-01-01',
750+
limit: 10,
751+
offset: 30,
752+
})
753+
expect(lastRequest()).toMatchObject({
754+
address: { relativePath: 'payrollRelationships/relationship%20key/child/payrollAssignments' },
755+
query: { limit: 10, offset: 30, effectiveDate: '2020-01-01' },
756+
})
757+
expect(result.output.payrollAssignments[0]).toMatchObject({
758+
payrollAssignmentId: '9007199254740993',
759+
assignmentId: '9007199254740995',
760+
timeCardRequired: 'Y',
761+
})
720762
expect(result.output.nextOffset).toBe(31)
721763
expect(mocks.requestOracleFusionJson).toHaveBeenCalledTimes(2)
722764
})
723765

724766
it.each([
725767
collection([], { limit: 2 }),
726-
collection([{ PayrollRelationshipId: '9', links: self('payrollRelationships/key') }], { limit: 2 }),
768+
collection([{ PayrollRelationshipId: '9', links: self('payrollRelationships/key') }], {
769+
limit: 2,
770+
}),
727771
collection([{ PayrollRelationshipId: '1', links: self('publicWorkers/key') }], { limit: 2 }),
728-
collection([{ PayrollRelationshipId: '1', links: self('payrollRelationships/key') }], { limit: 2, hasMore: true }),
729-
])('rejects missing, mismatched, foreign-parent, or ambiguous payroll resolution', async (response) => {
730-
mocks.requestOracleFusionJson.mockResolvedValueOnce(response)
731-
await expect(operations.executeOracleFusionHcmListPayrollAssignments({ ...auth, payrollRelationshipId: '1' })).rejects.toBeInstanceOf(OracleFusionProviderError)
732-
expect(mocks.requestOracleFusionJson).toHaveBeenCalledOnce()
733-
})
772+
collection([{ PayrollRelationshipId: '1', links: self('payrollRelationships/key') }], {
773+
limit: 2,
774+
hasMore: true,
775+
}),
776+
])(
777+
'rejects missing, mismatched, foreign-parent, or ambiguous payroll resolution',
778+
async (response) => {
779+
mocks.requestOracleFusionJson.mockResolvedValueOnce(response)
780+
await expect(
781+
operations.executeOracleFusionHcmListPayrollAssignments({
782+
...auth,
783+
payrollRelationshipId: '1',
784+
})
785+
).rejects.toBeInstanceOf(OracleFusionProviderError)
786+
expect(mocks.requestOracleFusionJson).toHaveBeenCalledOnce()
787+
}
788+
)
734789

735790
it('creates assigned payroll with all required dates and an exact numeric payroll ID', async () => {
736791
const assignmentPath = 'payrollRelationships/rel/child/payrollAssignments/asg'
737792
mocks.requestOracleFusionJson
738793
.mockResolvedValueOnce(discovery('payrollRelationships', 'PayrollRelationshipId', '1', 'rel'))
739-
.mockResolvedValueOnce(discovery('payrollRelationships/rel/child/payrollAssignments', 'RelationshipGroupId', '2', 'asg'))
740-
.mockResolvedValueOnce({ AssignedPayrollId: '3', PayrollId: '9223372036854775807', links: self(`${assignmentPath}/child/assignedPayrolls/new`) })
741-
await operations.executeOracleFusionHcmCreateAssignedPayroll({ ...auth, payrollRelationshipId: '1', payrollAssignmentId: '2', payrollId: '9223372036854775807', effectiveStartDate: '2026-01-01', effectiveEndDate: '4712-12-31', startDate: '2026-01-01', endDate: '4712-12-31' })
742-
expect(lastRequest()).toMatchObject({ address: { relativePath: `${assignmentPath}/child/assignedPayrolls` }, method: 'POST', mediaType: 'application/json' })
743-
expect(serializeOracleFusionJsonBody(lastRequest().body)).toBe('{"PayrollId":9223372036854775807,"EffectiveStartDate":"2026-01-01","EffectiveEndDate":"4712-12-31","StartDate":"2026-01-01","EndDate":"4712-12-31"}')
794+
.mockResolvedValueOnce(
795+
discovery(
796+
'payrollRelationships/rel/child/payrollAssignments',
797+
'RelationshipGroupId',
798+
'2',
799+
'asg'
800+
)
801+
)
802+
.mockResolvedValueOnce({
803+
AssignedPayrollId: '3',
804+
PayrollId: '9223372036854775807',
805+
links: self(`${assignmentPath}/child/assignedPayrolls/new`),
806+
})
807+
await operations.executeOracleFusionHcmCreateAssignedPayroll({
808+
...auth,
809+
payrollRelationshipId: '1',
810+
payrollAssignmentId: '2',
811+
payrollId: '9223372036854775807',
812+
effectiveStartDate: '2026-01-01',
813+
effectiveEndDate: '4712-12-31',
814+
startDate: '2026-01-01',
815+
endDate: '4712-12-31',
816+
})
817+
expect(lastRequest()).toMatchObject({
818+
address: { relativePath: `${assignmentPath}/child/assignedPayrolls` },
819+
method: 'POST',
820+
mediaType: 'application/json',
821+
})
822+
expect(serializeOracleFusionJsonBody(lastRequest().body)).toBe(
823+
'{"PayrollId":9223372036854775807,"EffectiveStartDate":"2026-01-01","EffectiveEndDate":"4712-12-31","StartDate":"2026-01-01","EndDate":"4712-12-31"}'
824+
)
744825
})
745826

746827
it('updates only assigned-payroll fields and sends an explicit effective-dating header', async () => {
747-
const collectionPath = 'payrollRelationships/rel/child/payrollAssignments/asg/child/assignedPayrolls'
828+
const collectionPath =
829+
'payrollRelationships/rel/child/payrollAssignments/asg/child/assignedPayrolls'
748830
mocks.requestOracleFusionJson
749831
.mockResolvedValueOnce(discovery('payrollRelationships', 'PayrollRelationshipId', '1', 'rel'))
750832
.mockResolvedValueOnce(discovery('payrollRelationships/rel/child/payrollAssignments', 'RelationshipGroupId', '2', 'asg'))

0 commit comments

Comments
 (0)