Skip to content

Commit daa123f

Browse files
Bill LeoutsakosBill Leoutsakos
authored andcommitted
fix(oracle-hcm): expose deliberate element value clearing
1 parent 7751a66 commit daa123f

9 files changed

Lines changed: 239 additions & 36 deletions

File tree

apps/docs/content/docs/integrations/oracle_fusion_hcm.mdx

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,8 @@ Salary creation and correction support **user-entered salary bases only**. Creat
4747

4848
Payroll run-result values, balance slots, and goal completion percentages remain their documented strings. Balance `value1``value10`, definition IDs, and context/dimension labels are preserved without inventing net-pay or year-to-date meanings.
4949

50+
When updating an element input value, supply its text value or explicitly enable `clearScreenEntryValue`. Clearing writes Oracle's documented null value; a missing value alone never clears it. Direct execution also accepts an explicit null. The clear flag follows the established integration pattern for model interfaces that cannot express nullable scalar parameters.
51+
5052
Operation contracts: [assigned payroll creation](https://docs.oracle.com/en/cloud/saas/human-resources/farws/op-payrollrelationships-payrollrelationshipsuniqid-child-payrollassignments-payrollassignmentsuniqid-child-assignedpayrolls-post.html), [element entry creation](https://docs.oracle.com/en/cloud/saas/human-resources/farws/op-elemententries-post.html), [salary creation](https://docs.oracle.com/en/cloud/saas/human-resources/farws/op-salaries-post.html), [salary correction](https://docs.oracle.com/en/cloud/saas/human-resources/farws/op-salaries-salaryid-patch.html), and [salary bases](https://docs.oracle.com/en/cloud/saas/human-resources/farws/op-salarybasislov-get.html). Required fields follow the formal operation schemas even where abbreviated examples omit them.
5153

5254
## Talent and performance
@@ -670,7 +672,8 @@ Update Element Entry Value using documented Oracle fields. Requires administrati
670672
| `elementEntryValueId` | string | Yes | Element entry value ID, as a positive decimal string |
671673
| `effectiveDate` | string | Yes | Effective date in YYYY-MM-DD format |
672674
| `rangeMode` | string | Yes | CORRECTION changes the historical row; UPDATE starts an effective-dated change |
673-
| `screenEntryValue` | string | No | Element input value as text, preserving decimal precision; null clears a nullable value |
675+
| `screenEntryValue` | string | No | Element input value as text, preserving decimal precision. To clear it, use clearScreenEntryValue. Direct execution also accepts explicit null. |
676+
| `clearScreenEntryValue` | boolean | No | Explicitly clear the element input value; omit screenEntryValue when true |
674677

675678
#### Output
676679

apps/sim/blocks/blocks/oracle_fusion_hcm.ts

Lines changed: 104 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1119,9 +1119,15 @@ export const OracleFusionHcmBlock: BlockConfig = {
11191119
title: 'Screen Entry Value',
11201120
type: 'short-input',
11211121
condition: { field: 'operation', value: ['update_element_entry_value'] },
1122-
required: { field: 'operation', value: ['update_element_entry_value'] },
11231122
description:
1124-
'Element input value as text, preserving decimal precision; null clears a nullable value',
1123+
'Set a text value or enable Clear Entry Value. Direct execution also accepts explicit null.',
1124+
},
1125+
{
1126+
id: 'clearScreenEntryValue',
1127+
title: 'Clear Entry Value',
1128+
type: 'switch',
1129+
condition: { field: 'operation', value: ['update_element_entry_value'] },
1130+
description: 'Explicitly clear the value. Leave Screen Entry Value blank when enabled.',
11251131
},
11261132
{
11271133
id: 'objectActionId',
@@ -1432,15 +1438,34 @@ export const OracleFusionHcmBlock: BlockConfig = {
14321438
type: 'short-input',
14331439
canonicalParamId: 'profileId',
14341440
mode: 'advanced',
1435-
condition: { field: 'operation', value: ['get_talent_profile', 'list_talent_profile_sections', 'list_talent_profile_skills', 'list_talent_profile_certifications'] },
1436-
required: { field: 'operation', value: ['get_talent_profile', 'list_talent_profile_sections', 'list_talent_profile_skills', 'list_talent_profile_certifications'] },
1441+
condition: {
1442+
field: 'operation',
1443+
value: [
1444+
'get_talent_profile',
1445+
'list_talent_profile_sections',
1446+
'list_talent_profile_skills',
1447+
'list_talent_profile_certifications',
1448+
],
1449+
},
1450+
required: {
1451+
field: 'operation',
1452+
value: [
1453+
'get_talent_profile',
1454+
'list_talent_profile_sections',
1455+
'list_talent_profile_skills',
1456+
'list_talent_profile_certifications',
1457+
],
1458+
},
14371459
placeholder: 'Enter profile id',
14381460
},
14391461
{
14401462
id: 'sectionKind',
14411463
title: 'Section Kind',
14421464
type: 'dropdown',
1443-
options: [{ id: 'skill', label: 'skill' }, { id: 'certification', label: 'certification' }],
1465+
options: [
1466+
{ id: 'skill', label: 'skill' },
1467+
{ id: 'certification', label: 'certification' },
1468+
],
14441469
value: () => 'skill',
14451470
condition: { field: 'operation', value: ['list_talent_profile_sections'] },
14461471
required: { field: 'operation', value: [] },
@@ -1450,15 +1475,24 @@ export const OracleFusionHcmBlock: BlockConfig = {
14501475
id: 'profileSectionId',
14511476
title: 'Profile Section Id',
14521477
type: 'short-input',
1453-
condition: { field: 'operation', value: ['list_talent_profile_skills', 'list_talent_profile_certifications'] },
1454-
required: { field: 'operation', value: ['list_talent_profile_skills', 'list_talent_profile_certifications'] },
1478+
condition: {
1479+
field: 'operation',
1480+
value: ['list_talent_profile_skills', 'list_talent_profile_certifications'],
1481+
},
1482+
required: {
1483+
field: 'operation',
1484+
value: ['list_talent_profile_skills', 'list_talent_profile_certifications'],
1485+
},
14551486
description: 'Profile section ID, as a positive decimal string',
14561487
},
14571488
{
14581489
id: 'startTime',
14591490
title: 'Start Time',
14601491
type: 'short-input',
1461-
condition: { field: 'operation', value: ['list_time_records', 'list_time_cards', 'create_time_entry', 'update_time_entry'] },
1492+
condition: {
1493+
field: 'operation',
1494+
value: ['list_time_records', 'list_time_cards', 'create_time_entry', 'update_time_entry'],
1495+
},
14621496
required: { field: 'operation', value: ['list_time_records', 'list_time_cards'] },
14631497
description: 'Start timestamp in ISO 8601 with explicit time-zone offset',
14641498
wandConfig: {
@@ -1472,7 +1506,10 @@ export const OracleFusionHcmBlock: BlockConfig = {
14721506
id: 'stopTime',
14731507
title: 'Stop Time',
14741508
type: 'short-input',
1475-
condition: { field: 'operation', value: ['list_time_records', 'list_time_cards', 'create_time_entry', 'update_time_entry'] },
1509+
condition: {
1510+
field: 'operation',
1511+
value: ['list_time_records', 'list_time_cards', 'create_time_entry', 'update_time_entry'],
1512+
},
14761513
required: { field: 'operation', value: ['list_time_records', 'list_time_cards'] },
14771514
description: 'Stop timestamp in ISO 8601 with explicit time-zone offset',
14781515
wandConfig: {
@@ -1486,8 +1523,14 @@ export const OracleFusionHcmBlock: BlockConfig = {
14861523
id: 'timeRecordId',
14871524
title: 'Time Record Id',
14881525
type: 'short-input',
1489-
condition: { field: 'operation', value: ['get_time_record', 'update_time_entry', 'delete_time_entry'] },
1490-
required: { field: 'operation', value: ['get_time_record', 'update_time_entry', 'delete_time_entry'] },
1526+
condition: {
1527+
field: 'operation',
1528+
value: ['get_time_record', 'update_time_entry', 'delete_time_entry'],
1529+
},
1530+
required: {
1531+
field: 'operation',
1532+
value: ['get_time_record', 'update_time_entry', 'delete_time_entry'],
1533+
},
14911534
description: 'Time record ID, as a positive decimal string',
14921535
},
14931536
{
@@ -1507,8 +1550,14 @@ export const OracleFusionHcmBlock: BlockConfig = {
15071550
serviceId: 'oracle_fusion_hcm',
15081551
dependsOn: ['oauthCredential'],
15091552
mode: 'basic',
1510-
condition: { field: 'operation', value: ['list_time_attribute_data_sources', 'list_time_attribute_criteria_binds'] },
1511-
required: { field: 'operation', value: ['list_time_attribute_data_sources', 'list_time_attribute_criteria_binds'] },
1553+
condition: {
1554+
field: 'operation',
1555+
value: ['list_time_attribute_data_sources', 'list_time_attribute_criteria_binds'],
1556+
},
1557+
required: {
1558+
field: 'operation',
1559+
value: ['list_time_attribute_data_sources', 'list_time_attribute_criteria_binds'],
1560+
},
15121561
placeholder: 'Select time attribute id',
15131562
description: 'Time attribute ID, as a positive decimal string',
15141563
},
@@ -1518,23 +1567,43 @@ export const OracleFusionHcmBlock: BlockConfig = {
15181567
type: 'short-input',
15191568
canonicalParamId: 'timeAttributeId',
15201569
mode: 'advanced',
1521-
condition: { field: 'operation', value: ['list_time_attribute_data_sources', 'list_time_attribute_criteria_binds'] },
1522-
required: { field: 'operation', value: ['list_time_attribute_data_sources', 'list_time_attribute_criteria_binds'] },
1570+
condition: {
1571+
field: 'operation',
1572+
value: ['list_time_attribute_data_sources', 'list_time_attribute_criteria_binds'],
1573+
},
1574+
required: {
1575+
field: 'operation',
1576+
value: ['list_time_attribute_data_sources', 'list_time_attribute_criteria_binds'],
1577+
},
15231578
placeholder: 'Enter time attribute id',
15241579
},
15251580
{
15261581
id: 'dataSourceUsageId',
15271582
title: 'Data Source Usage Id',
15281583
type: 'short-input',
1529-
condition: { field: 'operation', value: ['list_time_attribute_criteria_binds', 'list_time_attribute_values', 'create_time_entry', 'update_time_entry'] },
1530-
required: { field: 'operation', value: ['list_time_attribute_criteria_binds', 'list_time_attribute_values'] },
1584+
condition: {
1585+
field: 'operation',
1586+
value: [
1587+
'list_time_attribute_criteria_binds',
1588+
'list_time_attribute_values',
1589+
'create_time_entry',
1590+
'update_time_entry',
1591+
],
1592+
},
1593+
required: {
1594+
field: 'operation',
1595+
value: ['list_time_attribute_criteria_binds', 'list_time_attribute_values'],
1596+
},
15311597
description: 'Data source usage ID, as a positive decimal string',
15321598
},
15331599
{
15341600
id: 'timeAttributeUsageId',
15351601
title: 'Time Attribute Usage Id',
15361602
type: 'short-input',
1537-
condition: { field: 'operation', value: ['list_time_attribute_values', 'create_time_entry', 'update_time_entry'] },
1603+
condition: {
1604+
field: 'operation',
1605+
value: ['list_time_attribute_values', 'create_time_entry', 'update_time_entry'],
1606+
},
15381607
required: { field: 'operation', value: ['list_time_attribute_values'] },
15391608
description: 'Time attribute usage ID, as a positive decimal string',
15401609
},
@@ -1577,7 +1646,13 @@ export const OracleFusionHcmBlock: BlockConfig = {
15771646
canonicalParamId: 'payrollTimeType',
15781647
selectorKey: 'oracle_fusion_hcm.payrollTimeTypes',
15791648
serviceId: 'oracle_fusion_hcm',
1580-
dependsOn: ['oauthCredential', 'assignmentId', 'effectiveDate', 'dataSourceUsageId', 'timeAttributeUsageId'],
1649+
dependsOn: [
1650+
'oauthCredential',
1651+
'assignmentId',
1652+
'effectiveDate',
1653+
'dataSourceUsageId',
1654+
'timeAttributeUsageId',
1655+
],
15811656
mode: 'basic',
15821657
condition: { field: 'operation', value: ['create_time_entry', 'update_time_entry'] },
15831658
required: { field: 'operation', value: [] },
@@ -1805,6 +1880,11 @@ export const OracleFusionHcmBlock: BlockConfig = {
18051880
rest[key] = undefined
18061881
}
18071882
}
1883+
if (rest.clearScreenEntryValue === 'true') rest.clearScreenEntryValue = true
1884+
if (rest.clearScreenEntryValue === 'false') rest.clearScreenEntryValue = false
1885+
if (rest.screenEntryValue === '') {
1886+
rest.screenEntryValue = undefined
1887+
}
18081888
for (const key of ['limit', 'offset', 'salaryAmount', 'measure', 'timeRecordVersion'] as const) {
18091889
if (typeof rest[key] === 'string') rest[key] = Number(rest[key])
18101890
}
@@ -1845,7 +1925,11 @@ export const OracleFusionHcmBlock: BlockConfig = {
18451925
entryType: { type: 'string', description: 'Oracle element-entry type code supported by the tenant' },
18461926
entryValues: { type: 'json', description: 'Up to 100 typed objects: inputValueId (positive decimal string) and screenEntryValue (string up to 60 characters or null). Input IDs serialize exactly as JSON integers' },
18471927
elementEntryValueId: { type: 'string', description: 'Element entry value ID, as a positive decimal string' },
1848-
screenEntryValue: { type: 'string', description: 'Element input value as text, preserving decimal precision; null clears a nullable value' },
1928+
screenEntryValue: {
1929+
type: 'string',
1930+
description: 'Element input value as text; use clearScreenEntryValue to explicitly clear it',
1931+
},
1932+
clearScreenEntryValue: { type: 'boolean', description: 'Explicitly clear the element input value' },
18491933
objectActionId: { type: 'string', description: 'Object action ID, as a positive decimal string' },
18501934
salaryId: { type: 'string', description: 'Salary ID, as a positive decimal string' },
18511935
salaryBasisId: { type: 'string', description: 'Salary basis ID, as a positive decimal string' },

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

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,25 @@ function invokeHcmTool(overrides: Partial<InternalToolOperationCall>) {
8282
}
8383

8484
describe('Oracle Fusion HCM tool dispatch', () => {
85+
it('turns an explicit model clear flag into a nullable element value before execution', async () => {
86+
const response = await invokeHcmTool({
87+
toolId: 'oracle_fusion_hcm_update_element_entry_value',
88+
input: {
89+
...auth,
90+
elementEntryId: '1',
91+
elementEntryValueId: '2',
92+
effectiveDate: '2026-01-01',
93+
rangeMode: 'CORRECTION',
94+
clearScreenEntryValue: true,
95+
},
96+
})
97+
expect(response.status).toBe(200)
98+
expect(mocks.updateElementEntryValue).toHaveBeenCalledWith(
99+
expect.objectContaining({ screenEntryValue: null }),
100+
undefined
101+
)
102+
})
103+
85104
it('marks ambiguous mutation failures non-retryable without exposing provider details', async () => {
86105
mocks.createSalary.mockRejectedValueOnce(
87106
new OracleFusionProviderError('Oracle Fusion HCM request timed out', 504)

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

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1181,6 +1181,21 @@ describe('Oracle Fusion HCM payroll, compensation, talent, and time', () => {
11811181
method: 'POST',
11821182
body: {
11831183
processInline: 'N',
1184+
processMode: 'TIME_ENTER',
1185+
timeRecordEvent: [
1186+
expect.objectContaining({
1187+
operationType,
1188+
reporterIdType: 'PERSON',
1189+
reporterId: '0007',
1190+
}),
1191+
],
1192+
},
1193+
})
1194+
expect(result.output.timeRecordRequest.timeRecordEventRequestId).toBe('9007199254740993')
1195+
expect(result.output.timeRecordRequest).not.toHaveProperty('status')
1196+
expect(mocks.requestOracleFusionJson).toHaveBeenCalledOnce()
1197+
}
1198+
)
11841199

11851200
it('sends only a changed stop time for a versioned time-entry update', async () => {
11861201
mocks.requestOracleFusionJson.mockResolvedValueOnce({

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

Lines changed: 24 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -914,11 +914,29 @@ describe('Oracle Fusion HCM payroll and time input contracts', () => {
914914
})
915915

916916
it('preserves documented string-valued result, goal, flag, and message fields', () => {
917-
expect(projectors.projectPayrollRunResult({ RunResultId: '1', ResultValue: '123456789012345.6700' }).resultValue).toBe('123456789012345.6700')
918-
expect(projectors.projectPayrollBalance({ Value10: '0.0000', TotalValue1: null }).value10).toBe('0.0000')
919-
expect(projectors.projectPerformanceGoal({ GoalId: '2', PercentComplete: '25' }).percentComplete).toBe('25')
920-
expect(projectors.projectSalary({ SalaryId: '3', PendingTransactionExists: 'N' }).pendingTransactionExists).toBe('N')
921-
expect(projectors.projectTimeRecordEventMessage({ timeRecordEventMessageId: '4', allowException: 'N' }).allowException).toBe('N')
922-
expect(projectors.projectTimeRecordRequestEvent({ timeRecordEventId: '5', reporterId: '0007' }).reporterId).toBe('0007')
917+
expect(
918+
projectors.projectPayrollRunResult({ RunResultId: '1', ResultValue: '123456789012345.6700' })
919+
.resultValue
920+
).toBe('123456789012345.6700')
921+
expect(projectors.projectPayrollBalance({ Value10: '0.0000', TotalValue1: null }).value10).toBe(
922+
'0.0000'
923+
)
924+
expect(
925+
projectors.projectPerformanceGoal({ GoalId: '2', PercentComplete: '25' }).percentComplete
926+
).toBe('25')
927+
expect(
928+
projectors.projectSalary({ SalaryId: '3', PendingTransactionExists: 'N' })
929+
.pendingTransactionExists
930+
).toBe('N')
931+
expect(
932+
projectors.projectTimeRecordEventMessage({
933+
timeRecordEventMessageId: '4',
934+
allowException: 'N',
935+
}).allowException
936+
).toBe('N')
937+
expect(
938+
projectors.projectTimeRecordRequestEvent({ timeRecordEventId: '5', reporterId: '0007' })
939+
.reporterId
940+
).toBe('0007')
923941
})
924942
})

apps/sim/lib/internal/oracle-fusion-hcm/schema.ts

Lines changed: 21 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1641,13 +1641,27 @@ export type OracleFusionHcmCreateElementEntryResponse = z.output<
16411641
typeof oracleFusionHcmCreateElementEntryResponseSchema
16421642
>
16431643

1644-
export const oracleFusionHcmUpdateElementEntryValueBodySchema = oracleFusionHcmBaseBodySchema.extend({
1645-
elementEntryId: oracleFusionHcmDecimalIdSchema,
1646-
elementEntryValueId: oracleFusionHcmDecimalIdSchema,
1647-
effectiveDate: dateSchema,
1648-
rangeMode: z.enum(['CORRECTION', 'UPDATE']),
1649-
screenEntryValue: z.string().max(60).nullable(),
1650-
})
1644+
export const oracleFusionHcmUpdateElementEntryValueBodySchema = oracleFusionHcmBaseBodySchema
1645+
.extend({
1646+
elementEntryId: oracleFusionHcmDecimalIdSchema,
1647+
elementEntryValueId: oracleFusionHcmDecimalIdSchema,
1648+
effectiveDate: dateSchema,
1649+
rangeMode: z.enum(['CORRECTION', 'UPDATE']),
1650+
screenEntryValue: z.string().min(1).max(60).nullable().optional(),
1651+
clearScreenEntryValue: z.boolean().optional(),
1652+
})
1653+
.superRefine((input, context) => {
1654+
if (input.screenEntryValue === undefined && input.clearScreenEntryValue !== true) {
1655+
context.addIssue({ code: 'custom', message: 'Supply screenEntryValue or explicitly clear it' })
1656+
}
1657+
if (input.clearScreenEntryValue && input.screenEntryValue != null) {
1658+
context.addIssue({ code: 'custom', message: 'Cannot set and clear screenEntryValue together' })
1659+
}
1660+
})
1661+
.transform((input) => ({
1662+
...input,
1663+
screenEntryValue: input.clearScreenEntryValue ? null : (input.screenEntryValue ?? null),
1664+
}))
16511665

16521666
export const oracleFusionHcmUpdateElementEntryValueResponseSchema = successResponse(
16531667
z.object({

apps/sim/tools/generated/tool-metadata.ts

Lines changed: 1 addition & 1 deletion
Large diffs are not rendered by default.

0 commit comments

Comments
 (0)