Showing posts with label Oracle Cloud Technical. Show all posts
Showing posts with label Oracle Cloud Technical. Show all posts

Monday, 15 June 2026

Oracle Cloud Payroll Costing: SQL Queries to Identify Missing Assignment and Department Costing

Oracle Cloud Payroll Costing: SQL Queries to Identify Missing Assignment and Department Costing

Introduction

Payroll costing is one of the most critical configuration areas in Oracle Cloud Payroll. If costing is missing or incomplete, payroll may still calculate successfully, but downstream accounting, costing, and General Ledger transfer can become challenging.

In real implementations, payroll and finance teams often ask questions such as:

  • Which employees do not have assignment-level costing?
  • Which departments do not have department-level costing?
  • Which employees are assigned to departments where costing has not been configured?

These are simple questions from a business perspective, but they are not always easy to answer from the UI, especially when the population is large.

This blog shares three useful SQL queries that can help implementation and support teams identify gaps in payroll costing setup.


Why This Matters

Missing costing setup can cause issues such as:

  • Payroll costs going to suspense accounts
  • Incorrect cost center allocation
  • Payroll costing transfer failures
  • Reconciliation issues between Payroll and GL
  • Manual cleanup during payroll close
  • Delays in payroll accounting validation

During implementation, parallel payroll, or post-production support, these queries can be very helpful for proactive validation.


Query 1: List Employees Without Assignment Costing

Business Requirement

The first requirement is to identify active employees who do not have assignment-level costing configured.

Assignment costing is often used when payroll costs should be charged directly based on the employee assignment rather than defaulting from department, position, organization, or other costing hierarchy levels.

SQL Query

SELECT 
    papf.person_number,
    paam.assignment_number,
    paam.assignment_name,
    cost_acc.*
FROM
(
    SELECT
        TO_CHAR(pcaf.effective_start_date, 'YYYY/MM/DD') pcaf_effective_start_date,
        TO_CHAR(pcaf.effective_end_date, 'YYYY/MM/DD') pcaf_effective_end_date,
        pcaf.payroll_relationship_id,
        TO_CHAR(pcaa.cost_alloc_account_id) cost_alloc_account_id,
        TO_CHAR(pcaa.cost_allocation_record_id) cost_allocation_record_id,
        pcaa.id_flex_num,
        TO_CHAR(pcaa.cost_allocation_keyflex_id) cost_allocation_keyflex_id,
        pcaa.proportion,
        pcaa.source_sub_type,
        pcaa.segment1,
        pcaa.segment2 seg2_location,
        pcaa.segment3 seg3_division,
        pcaa.segment4,
        pcaa.segment5,
        pcaa.segment6,
        pcaa.segment7,
        pcaa.segment8,
        pcaa.segment9,
        pcaa.segment10,
        pcaa.created_by,
        pcaa.creation_date,
        pcaa.last_update_date,
        pcaa.last_update_login,
        pcaa.last_updated_by
    FROM 
        pay_cost_allocations_f pcaf,
        pay_cost_alloc_accounts pcaa
    WHERE 
        pcaf.cost_allocation_record_id(+) = pcaa.cost_allocation_record_id
        AND pcaf.source_type(+) = 'ASG'
        AND pcaf.payroll_relationship_id IN 
        (
            SELECT payroll_relationship_id
            FROM pay_pay_relationships_dn
            WHERE person_id IN 
            (
                SELECT DISTINCT person_id
                FROM per_all_people_f
            )
        )
) cost_acc,
per_all_assignments_m paam,
per_all_people_f papf,
pay_pay_relationships_dn pprd
WHERE
    cost_acc.payroll_relationship_id(+) = pprd.payroll_relationship_id
    AND papf.person_id = paam.person_id
    AND papf.person_id = pprd.person_id
    AND paam.assignment_type NOT LIKE '%Termi%'
    AND paam.assignment_type = 'E'
    AND paam.assignment_status_type = 'ACTIVE'
    AND TRUNC(SYSDATE) BETWEEN paam.effective_start_date AND paam.effective_end_date
    AND TRUNC(SYSDATE) BETWEEN papf.effective_start_date AND papf.effective_end_date;

How to Use the Output

This query returns active employee assignments along with assignment costing details if they exist.

To identify employees missing assignment costing, review records where costing segments or costing account information are blank.

Depending on your reporting requirement, you may further add a filter such as:

AND cost_acc.cost_allocation_record_id IS NULL

or check a specific costing segment, for example:

AND cost_acc.segment4 IS NULL

Practical Use Case

This query is useful during:

  • Payroll implementation validation
  • Pre-parallel payroll checks
  • Assignment costing cleanup
  • Payroll costing troubleshooting
  • Post-go-live support (every pre-payroll validation report before every payroll run)

Query 2: List Departments Without Costing Information

Business Requirement

The second requirement is to identify departments where costing has not been configured.

Department costing is commonly used as a default costing level. If employee assignment costing is not available, payroll may derive costing from the department or organization level depending on the costing hierarchy.

SQL Query

SELECT
    hov.name department_name,
    cost_acc.*
FROM 
(
    SELECT
        TO_CHAR(pcaf.effective_start_date, 'YYYY/MM/DD') costing_effective_start_date,
        TO_CHAR(pcaf.effective_end_date, 'YYYY/MM/DD') costing_effective_end_date,
        pcaf.source_id,
        TO_CHAR(pcaa.cost_alloc_account_id) cost_alloc_account_id,
        TO_CHAR(pcaa.cost_allocation_record_id) cost_allocation_record_id,
        pcaa.id_flex_num,
        TO_CHAR(pcaa.cost_allocation_keyflex_id) cost_allocation_keyflex_id,
        pcaa.proportion,
        pcaa.source_sub_type,
        pcaa.segment1,
        pcaa.segment2 seg2_location,
        pcaa.segment3 seg3_division,
        pcaa.segment4 seg4_cost_center,
        pcaa.segment5,
        pcaa.segment6,
        pcaa.segment7,
        pcaa.segment8,
        pcaa.segment9,
        pcaa.segment10,
        pcaa.created_by,
        pcaa.creation_date,
        pcaa.last_update_date,
        pcaa.last_update_login,
        pcaa.last_updated_by
    FROM
        pay_cost_alloc_accounts pcaa,
        pay_cost_allocations_f pcaf
    WHERE
        pcaa.source_sub_type = 'COST'
        AND pcaf.source_type(+) = 'ORG'
        AND pcaa.cost_allocation_record_id = pcaf.cost_allocation_record_id(+)
) cost_acc,
hr_organization_v hov
WHERE
    cost_acc.source_id(+) = hov.organization_id
    AND hov.classification_code = 'DEPARTMENT'
    AND TRUNC(SYSDATE) BETWEEN hov.effective_start_date AND hov.effective_end_date;

How to Use the Output

This query lists departments and any associated organization-level costing details.

To identify only departments missing costing, you can add a filter such as:

AND cost_acc.cost_allocation_record_id IS NULL

or if Cost Center is stored in Segment 4:

AND cost_acc.seg4_cost_center IS NULL

Practical Use Case

This query is useful when Finance or Payroll wants to validate whether every active department has costing configured before payroll costing is transferred to GL.


Query 3: List Employees Assigned to Departments Without Costing

Business Requirement

The third requirement combines employee assignment data with department costing data.

This is especially useful because a department may be missing costing, but the real operational impact depends on whether active employees are assigned to that department.

SQL Query

SELECT
    papf.person_number,
    paam.assignment_number,
    pd.name department_name,
    cost_acc.*
FROM
    per_all_people_f papf,
    per_all_assignments_m paam,
    per_periods_of_service ppos,
    per_departments pd,
    (
        SELECT
            TO_CHAR(pcaf.effective_start_date, 'YYYY/MM/DD') pcaf_effective_start_date,
            TO_CHAR(pcaf.effective_end_date, 'YYYY/MM/DD') pcaf_effective_end_date,
            pcaf.source_id,
            pcaf.source_type,
            pcaf.payroll_relationship_id,
            TO_CHAR(pcaa.cost_alloc_account_id) cost_alloc_account_id,
            TO_CHAR(pcaa.cost_allocation_record_id) cost_allocation_record_id,
            pcaa.id_flex_num,
            TO_CHAR(pcaa.cost_allocation_keyflex_id) cost_allocation_keyflex_id,
            pcaa.proportion,
            pcaa.source_sub_type,
            pcaa.segment1,
            pcaa.segment2 seg2_location,
            pcaa.segment3 seg3_division,
            pcaa.segment4 seg4_cost_center,
            pcaa.segment5,
            pcaa.segment6,
            pcaa.segment7,
            pcaa.segment8,
            pcaa.segment9,
            pcaa.segment10,
            pcaa.created_by,
            pcaa.creation_date,
            pcaa.last_update_date,
            pcaa.last_update_login,
            pcaa.last_updated_by
        FROM
            pay_cost_alloc_accounts pcaa,
            pay_cost_allocations_f pcaf
        WHERE
            pcaa.source_sub_type = 'COST'
            AND pcaf.source_type(+) = 'ORG'
            AND pcaa.cost_allocation_record_id = pcaf.cost_allocation_record_id(+)
    ) cost_acc
WHERE
    papf.person_id = paam.person_id
    AND ppos.period_of_service_id = paam.period_of_service_id
    AND paam.organization_id = pd.organization_id(+)
    AND cost_acc.source_id(+) = pd.organization_id
    AND paam.assignment_type NOT LIKE '%Term%'
    AND TRUNC(SYSDATE) BETWEEN papf.effective_start_date AND papf.effective_end_date
    AND TRUNC(SYSDATE) BETWEEN pd.effective_start_date(+) AND pd.effective_end_date(+)
    AND TRUNC(SYSDATE) BETWEEN paam.effective_start_date AND paam.effective_end_date
    AND paam.primary_flag = 'Y'
    AND paam.assignment_type NOT LIKE '%Term%'
    AND paam.assignment_status_type = 'ACTIVE'
    AND paam.assignment_type = 'E'
    AND ppos.date_start =
    (
        SELECT MAX(date_start)
        FROM per_periods_of_service
        WHERE person_id = paam.person_id
        AND period_type = paam.assignment_type
    )
    AND
    (
        pd.name IS NULL
        OR cost_acc.seg4_cost_center IS NULL
    );

How to Use the Output

This query identifies active employees where:

  • No department is assigned
  • The assigned department does not have costing information

This is one of the most useful payroll costing audit queries because it directly shows impacted employees.

Practical Use Case

Use this query before:

  • Payroll costing process
  • Transfer to Subledger Accounting
  • Transfer to General Ledger
  • Parallel payroll validation
  • Department costing conversion signoff

Important Notes

1. Segment Names Are Client Specific

In the sample queries:

SEGMENT2 = Location
SEGMENT3 = Division
SEGMENT4 = Cost Center

However, your client’s costing key flexfield may be different.

Always confirm the costing segment structure before using the query in a production environment.

2. Costing Hierarchy Matters

Oracle Payroll costing can be derived from different levels, such as:

  • Element entry costing
  • Assignment costing
  • Department costing
  • Position costing
  • Organization costing
  • Element eligibility costing
  • Payroll relationship costing

These queries focus mainly on assignment and department-level costing.

If your client relies on other costing levels, additional queries may be required.

3. Date Effectivity Is Critical

Payroll costing is date-effective.

Always validate costing as of the correct date:

TRUNC(SYSDATE)

This may be fine for current-state validation, but for payroll processing you may need to replace it with:

:PAYROLL_PERIOD_END_DATE

or another parameterized effective date.

4. Outer Join Usage

These queries intentionally use outer joins to identify missing costing records.

That is why you see syntax such as:

cost_acc.source_id(+) = pd.organization_id

This allows departments or assignments to appear even when costing is missing.


Recommended Enhancements

For production reporting, I recommend enhancing these queries with parameters such as:

  • Effective date
  • Legislative Data Group
  • Payroll name
  • Legal employer
  • Department name
  • Person number
  • Assignment number
  • Cost center
  • Business unit

This makes the report more flexible for payroll and finance users.


When to Run These Queries

These queries are useful during:

  • Payroll implementation
  • Data conversion validation
  • Parallel payroll
  • Payroll costing testing
  • Pre-go-live readiness checks
  • Post-production audits
  • Payroll close activities
  • Post-go-live support (every pre-payroll validation report before every payroll run)

Final Thoughts

Payroll costing is often treated as a setup activity, but in practice it needs continuous validation.

Missing assignment or department costing can create downstream payroll accounting issues that are harder to fix after payroll has been processed.

These three SQL queries provide a practical way to identify:

  • Employees without assignment costing
  • Departments without costing
  • Employees assigned to departments without costing

For Oracle Cloud Payroll implementation teams, these reports can become part of a standard payroll costing readiness checklist before each major payroll milestone.

Used proactively, they can reduce payroll accounting errors, improve reconciliation, and help payroll and finance teams close payroll with more confidence.

Oracle Cloud Payroll: How to Load Personal Payment Methods Using HDL

Oracle Cloud Payroll: How to Load Personal Payment Methods Using HDL

Personal Payment Methods in Oracle Fusion HCM define how an employee receives payroll payments.

For example, an employee may receive:

  • 100 percent of their salary in one checking account
  • A fixed amount in a savings account
  • The remaining balance in another account

When loading a direct-deposit Personal Payment Method through HCM Data Loader (HDL), the Personal Payment Method cannot be created in isolation.

Oracle must first know the following hierarchy:

Bank
→ Bank Branch
→ External Bank Account
→ External Bank Account Owner
→ Personal Payment Method

In this article, we will load a bank account and create a Personal Payment Method that deposits 100 percent of the employee’s payroll payment into that account.


Example Data

Attribute Value
Person Number 82213
Assignment Number E82213
Bank Name BANK OF AMERICA
Routing Number 064000020
Branch Name BANK OF AMERICA - 064000020
Account Type Checking
Country US
Currency USD
Legislative Data Group US Legislative Data Group
Organization Payment Method DD
Payment Percentage 100
Processing Order 1

Note: The bank account number is masked in this article. Replace <BANK_ACCOUNT_NUMBER> with the actual account number in the secured HDL file.


Prerequisites

Before loading the Personal Payment Method, confirm that:

  • The employee exists in Oracle Fusion HCM.
  • Person number 82213 is valid.
  • Assignment number E82213 is valid.
  • The employee has a payroll relationship.
  • The assignment is associated with the required payroll.
  • US Legislative Data Group exists.
  • Organization Payment Method code DD exists.
  • The Organization Payment Method is effective on the Personal Payment Method start date.

The Organization Payment Method code is configured during payroll implementation. It may not always be DD, so confirm the value in the target environment.


Step 1: Load the Bank

Create a file named Bank.dat.

METADATA|Bank|BankName|CountryCode
MERGE|Bank|BANK OF AMERICA|US

This creates or identifies the bank using:

  • BankName: BANK OF AMERICA
  • CountryCode: US

If the bank already exists in Oracle with the same name and country, the existing bank can be used.

Bank names must be consistent across all the HDL files.

For example:

BANK OF AMERICA

and:

BANK OF AMERICA N.A.

may be treated as different bank names.




Step 2: Load the Bank Branch

Create a file named BankBranch.dat.

METADATA|BankBranch|BankName|CountryCode|BankBranchNumber|BankBranchName
MERGE|BankBranch|BANK OF AMERICA|US|064000020|BANK OF AMERICA - 064000020

The branch is associated with Bank of America using the bank name and country.

For example:

  • BankBranchNumber: 064000020
  • BankBranchName: BANK OF AMERICA - 064000020

For US bank accounts, the branch number normally represents the routing number.

The branch name can follow any agreed naming convention, but the same branch name must be used when loading the External Bank Account and Personal Payment Method.




Step 3a: Load the External Bank Account

Create a file named ExternalBankAccount.dat.

METADATA|ExternalBankAccount|BankName|BankBranchName|BankBranchNumber|AccountNumber|AccountType|AccountName|CountryCode|CurrencyCode
MERGE|ExternalBankAccount|BANK OF AMERICA|BANK OF AMERICA - 064000020|064000020|<BANK_ACCOUNT_NUMBER>|Checking||US|USD

This record creates an employee’s bank account.

The important attributes are:

  • BankName: BANK OF AMERICA
  • BankBranchName: BANK OF AMERICA - 064000020
  • BankBranchNumber: 064000020
  • AccountNumber: <BANK_ACCOUNT_NUMBER>
  • AccountType: Checking
  • CountryCode: US
  • CurrencyCode: USD

AccountName is left blank in this example.

It can also be populated with a description such as:

PRIMARY CHECKING ACCOUNT

The account-type value must be valid in the Oracle environment. Depending on the configured lookup values, the environment may expect a value such as Checking or CHECKING.


Step 3b: Load the External Bank Account Owner

Creating the External Bank Account does not automatically associate it with an employee.

The ExternalBankAccountOwner record establishes the ownership relationship.

Add the following record to ExternalBankAccount.dat:

METADATA|ExternalBankAccountOwner|PersonNumber|BankName|BankBranchName|AccountNumber|CountryCode|CurrencyCode|BankBranchNumber|AccountType|PrimaryFlag
MERGE|ExternalBankAccountOwner|82213|BANK OF AMERICA|BANK OF AMERICA - 064000020|<BANK_ACCOUNT_NUMBER>|US|USD|064000020|Checking|Y

The employee is identified using the person number:

PersonNumber: 82213

The employee is also marked as the primary account owner:

PrimaryFlag: Y

It is important to use the person number here, not the assignment number.

Combined ExternalBankAccount.dat File

METADATA|ExternalBankAccount|BankName|BankBranchName|BankBranchNumber|AccountNumber|AccountType|AccountName|CountryCode|CurrencyCode
MERGE|ExternalBankAccount|BANK OF AMERICA|BANK OF AMERICA - 064000020|064000020|<BANK_ACCOUNT_NUMBER>|Checking||US|USD

METADATA|ExternalBankAccountOwner|PersonNumber|BankName|BankBranchName|AccountNumber|CountryCode|CurrencyCode|BankBranchNumber|AccountType|PrimaryFlag
MERGE|ExternalBankAccountOwner|82213|BANK OF AMERICA|BANK OF AMERICA - 064000020|<BANK_ACCOUNT_NUMBER>|US|USD|064000020|Checking|Y

Uploading: 43601 of 43601 bytes uploaded.



Step 4: Load the Personal Payment Method

After the bank account and account owner are successfully loaded, create PersonalPaymentMethod.dat.

METADATA|PersonalPaymentMethod|EffectiveStartDate|EffectiveEndDate|PersonalPaymentMethodCode|PaymentAmountType|Percentage|ProcessingOrder|LegislativeDataGroupName|AssignmentNumber|OrganizationPaymentMethodCode|BankAccountNumber|BankBranchName|BankName|BankCountryCode|BankBranchNumber|BankAccountType
MERGE|PersonalPaymentMethod|2021/02/01|4712/12/31|PPM_82213_1|P|100|1|US Legislative Data Group|E82213|DD|<BANK_ACCOUNT_NUMBER>|BANK OF AMERICA - 064000020|BANK OF AMERICA|US|064000020|Checking

Let us look at the important attributes.





Effective Start and End Dates

EffectiveStartDate: 2021/02/01
EffectiveEndDate: 4712/12/31

The effective start date determines when the payment method becomes active.

The date must be valid for the employee’s:

  • Work relationship
  • Assignment
  • Payroll relationship
  • Organization Payment Method

4712/12/31 is commonly used as an open-ended effective end date.


Personal Payment Method Code

PersonalPaymentMethodCode: PPM_82213_1

This is the identifier for the Personal Payment Method.

A simple naming convention is:

PPM_<PERSON_NUMBER>_<SEQUENCE>

For example:

PPM_82213_1
PPM_82213_2

The second value can be used when an employee has multiple payment methods.


Payment Amount Type

PaymentAmountType: P

P represents a percentage-based payment method in this example.

Because the payment amount type is percentage, the Percentage attribute is populated:

Percentage: 100

This means that 100 percent of the applicable payroll payment will be deposited into the account.


Processing Order

ProcessingOrder: 1

Processing orders are important when an employee has multiple Personal Payment Methods.

For example:

  • Account 1: Processing order 1
  • Account 2: Processing order 2

Oracle processes the payment methods according to this sequence.


Legislative Data Group

LegislativeDataGroupName: US Legislative Data Group

The value must exactly match the Legislative Data Group configured in Oracle Fusion HCM.


Assignment Number

AssignmentNumber: E82213

The Personal Payment Method is associated with the employee’s payroll assignment using the assignment number.

This is different from the External Bank Account Owner record, which uses the person number.

ExternalBankAccountOwner → PersonNumber
PersonalPaymentMethod → AssignmentNumber

This is an important distinction when preparing the HDL files.


Organization Payment Method

OrganizationPaymentMethodCode: DD

The Organization Payment Method defines the payment mechanism used by payroll.

In this example, DD represents direct deposit.

The code must:

  • Exist in the target environment
  • Be associated with the correct Legislative Data Group
  • Be effective on the Personal Payment Method start date
  • Support the required payment type and currency

Bank Account Reference

The final attributes identify the External Bank Account:

  • BankAccountNumber
  • BankBranchName
  • BankName
  • BankCountryCode
  • BankBranchNumber
  • BankAccountType

The values must match the External Bank Account record.

For example:

  • BankAccountNumber: <BANK_ACCOUNT_NUMBER>
  • BankBranchName: BANK OF AMERICA - 064000020
  • BankName: BANK OF AMERICA
  • BankCountryCode: US
  • BankBranchNumber: 064000020
  • BankAccountType: Checking

Even a small difference in the bank or branch values can cause Oracle to report that the bank account cannot be found.


Recommended Load Order

Load the HDL files in the following sequence:

  1. Bank.dat
  2. BankBranch.dat
  3. ExternalBankAccount.dat
  4. PersonalPaymentMethod.dat

Validate each load before proceeding to the next file.

For example, do not load the Personal Payment Method until the External Bank Account and External Bank Account Owner have completed successfully.


Uploading the HDL Files

To upload the files:

  1. Save each file with the .dat extension.
  2. Place the .dat file inside a ZIP file.
  3. Navigate to My Client Groups.
  4. Open Data Exchange.
  5. Select Import and Load Data.
  6. Upload the ZIP file.
  7. Monitor the import and load processes.
  8. Review the object and component statuses.

If a record fails, download the error file and review the detailed error message.


Common Errors

Bank Could Not Be Found

Verify that:

  • The bank was loaded successfully.
  • The bank name matches exactly.
  • The country code is correct.
  • The same bank name is used in all files.

Bank Branch Could Not Be Found

Verify:

  • BankName
  • BankBranchName
  • BankBranchNumber
  • CountryCode

The branch name and routing number must match the Bank Branch record.

Also verify that leading zeros have not been removed from the routing number.

External Bank Account Could Not Be Found

Compare the following values between ExternalBankAccount.dat and PersonalPaymentMethod.dat:

  • AccountNumber
  • AccountType
  • BankName
  • BankBranchName
  • BankBranchNumber
  • CountryCode
  • CurrencyCode

The most common issue is a difference in one of the identifying values.

Account Owner Could Not Be Created

Verify that:

  • Person number 82213 exists.
  • The External Bank Account loaded successfully.
  • The person number, not the assignment number, is used.
  • PrimaryFlag contains a valid value.

Assignment Could Not Be Found

Verify that:

  • Assignment number E82213 exists.
  • The assignment is active on the effective start date.
  • The employee has a valid payroll relationship.
  • The assignment belongs to the expected legislative context.

Organization Payment Method Is Invalid

Verify that:

  • DD is the configured Organization Payment Method code.
  • It belongs to US Legislative Data Group.
  • It is effective on 2021/02/01.
  • It supports the required currency and payment method.

Account Type Is Invalid

Verify the accepted lookup value for the Account Type attribute.

The target environment may accept:

Checking

or may require a lookup code such as:

CHECKING

Use the value supported by the target Oracle environment.


Complete HDL Example

Bank.dat

METADATA|Bank|BankName|CountryCode
MERGE|Bank|BANK OF AMERICA|US

BankBranch.dat

METADATA|BankBranch|BankName|CountryCode|BankBranchNumber|BankBranchName
MERGE|BankBranch|BANK OF AMERICA|US|064000020|BANK OF AMERICA - 064000020

ExternalBankAccount.dat

METADATA|ExternalBankAccount|BankName|BankBranchName|BankBranchNumber|AccountNumber|AccountType|AccountName|CountryCode|CurrencyCode
MERGE|ExternalBankAccount|BANK OF AMERICA|BANK OF AMERICA - 064000020|064000020|<BANK_ACCOUNT_NUMBER>|Checking||US|USD

METADATA|ExternalBankAccountOwner|PersonNumber|BankName|BankBranchName|AccountNumber|CountryCode|CurrencyCode|BankBranchNumber|AccountType|PrimaryFlag
MERGE|ExternalBankAccountOwner|82213|BANK OF AMERICA|BANK OF AMERICA - 064000020|<BANK_ACCOUNT_NUMBER>|US|USD|064000020|Checking|Y

PersonalPaymentMethod.dat

METADATA|PersonalPaymentMethod|EffectiveStartDate|EffectiveEndDate|PersonalPaymentMethodCode|PaymentAmountType|Percentage|ProcessingOrder|LegislativeDataGroupName|AssignmentNumber|OrganizationPaymentMethodCode|BankAccountNumber|BankBranchName|BankName|BankCountryCode|BankBranchNumber|BankAccountType
MERGE|PersonalPaymentMethod|2021/02/01|4712/12/31|PPM_82213_1|P|100|1|US Legislative Data Group|E82213|DD|<BANK_ACCOUNT_NUMBER>|BANK OF AMERICA - 064000020|BANK OF AMERICA|US|064000020|Checking

Final Thoughts

The key to successfully loading a Personal Payment Method is understanding the dependency between the HDL business objects.

The Personal Payment Method is the final record in the following chain:

Bank
→ Bank Branch
→ External Bank Account
→ External Bank Account Owner
→ Personal Payment Method

Load and validate each object in sequence.

Also remember the two different worker identifiers used in the files:

Account owner → Person Number
Personal Payment Method → Assignment Number

Once the employee, payroll relationship, bank account, account owner, and Organization Payment Method are available, the Personal Payment Method can be loaded successfully using HDL.

Saturday, 13 June 2026

Oracle Cloud Payroll: Loading Payroll-Ready Time Transactions Using PayrollTimeCard HDL

Oracle Cloud Payroll: Loading Payroll-Ready Time Transactions Using PayrollTimeCard HDL

Introduction

Oracle Payroll provides a powerful HDL business object that is often overlooked:

PayrollTimeCard

This object allows organizations to load payroll-ready time transactions directly into Oracle Payroll.

This capability is particularly valuable when an external workforce management system is responsible for collecting, approving, and calculating employee time before it reaches Oracle.

Examples of external workforce management systems include:

  • UKG
  • Kronos
  • Workforce Software
  • ADP eTime
  • Workday Time Tracking
  • Custom Time Collection Applications

Instead of recreating complex time rules in Oracle, organizations can load the approved payroll-ready results.


A Common Misconception

One misconception I frequently encounter is that any time-related transaction must be loaded using:

  • Oracle Time and Labor
  • AbsenceEntry HDL
  • ElementEntry HDL

In reality, Oracle provides a dedicated HDL object specifically designed for payroll time transactions:

PayrollTimeCard

Another common misconception is that PayrollTimeCard is the same as a Payroll Calculation Card.

It is not.

Object Purpose
CalculationCard.dat Tax cards, involuntary deductions, benefits, pensions
PayrollTimeCard.dat Payroll-ready time transactions
AbsenceEntry.dat Absence transactions
ElementEntry.dat Payroll element entries

Understanding this distinction can simplify many integration designs.


Business Scenario

Consider a simple example.

An employee has:

4 Hours of OT Straight

on:

20-May-2026

The time has already been:

  • Entered
  • Approved
  • Calculated

within an external workforce management application.

The business does not want Oracle to:

  • Calculate time
  • Evaluate time rules
  • Recreate time calculation logic

Instead, Oracle Payroll simply needs the final transaction for payroll processing.

This is an ideal use case for PayrollTimeCard HDL.


Sample HDL

The following HDL creates both a payroll time card and a related time entry.

METADATA|PayrollTimeCard|LegislativeDataGroupName|AssignmentNumber|EffectiveStartDate|EffectiveEndDate|TimeCardId
MERGE|PayrollTimeCard|US Legislative Data Group|E100|2026/05/20|2026/05/20|10020260520

METADATA|TimeEntry|LegislativeDataGroupName|AssignmentNumber|EffectiveStartDate|EffectiveEndDate|TimeType|Time|UnitOfMeasure|TimeCardId|TimeEntryId|Periodicity|Factor|RateName|RateValue|Segment1
MERGE|TimeEntry|US Legislative Data Group|E100|2026/05/20|2026/05/20|OT Straight|4|H_DECIMAL3|10020260520|1002026052001|HOURLY||||

Understanding the PayrollTimeCard Record

The first section creates the parent payroll time card.

MERGE|PayrollTimeCard|US Legislative Data Group|E100|2026/05/20|2026/05/20|10020260520

Legislative Data Group

US Legislative Data Group

Defines the legislative context.

Assignment Number

E100

Identifies the employee assignment.

Effective Dates

2026/05/20

Represents the date associated with the payroll transaction.

TimeCardId

10020260520

Acts as the parent identifier used to associate TimeEntry records with the time card.


Understanding the TimeEntry Record

The second section creates the actual payroll transaction.

MERGE|TimeEntry|US Legislative Data Group|E100|2026/05/20|2026/05/20|OT Straight|4|H_DECIMAL3|10020260520|1002026052001|HOURLY||||

Time Type

OT Straight

Identifies the type of payroll time being loaded.

Examples include:

  • OT Straight
  • Overtime
  • Double Time
  • Shift Differential

Time

4

Represents the quantity.

Unit of Measure

H_DECIMAL3

Indicates hours with three-decimal precision.

Examples:

8.000
4.500
2.250

TimeEntryId

1002026052001

Unique identifier for the individual time transaction.

Periodicity

HOURLY

Defines how Payroll interprets the transaction.





Why Use PayrollTimeCard HDL?

Many organizations already have mature workforce management platforms.

These systems may already calculate:

  • Overtime
  • Double Time
  • Shift Premiums
  • Call Back Pay
  • On Call Pay
  • Hazard Pay

Recreating those same calculations in Oracle often leads to:

  • Duplicate rule maintenance
  • Increased testing effort
  • Additional support overhead

Using PayrollTimeCard HDL allows Oracle Payroll to consume the final approved results.


Additional Attributes and Costing

TimeEntry supports additional attributes that can be used for labor allocation and payroll processing.

Examples include:

Segment1
Segment2
Segment3

These attributes can be leveraged to pass:

  • Cost centers
  • Departments
  • Projects
  • Labor allocations

from external systems into Oracle Payroll.

This can be especially useful when integrating with UKG or Kronos labor tracking structures.


Rollback Capability

One of the most useful features of HDL is the ability to roll back a load.

If an incorrect time card is loaded:

  • A separate delete HDL file is not required
  • Administrators can roll back the HDL load
  • Correct the source file
  • Reload the transactions

This significantly simplifies:

  • Testing
  • Data conversion
  • Payroll parallel runs
  • Production support

Compared to manually creating reversal HDL files, rollback can save considerable effort.





Typical Use Cases

I commonly see PayrollTimeCard HDL used for:

UKG Integrations

Loading approved payroll hours directly into Oracle Payroll.

Kronos Integrations

Loading overtime, premiums, and shift differentials.

Workforce Software Integrations

Passing final payroll-ready transactions.

Legacy Time Systems

Migrating approved time transactions into Oracle.

Payroll Conversion Projects

Loading historical payroll time transactions during implementation.


Testing Recommendations

Before moving to production, validate:

  • HDL load success
  • PayrollTimeCard creation
  • TimeEntry creation
  • Payroll calculation results
  • Time type mappings
  • Labor allocation values
  • Payroll balances
  • Retro processing behavior

Particular attention should be paid to overtime and premium calculations when external systems are performing the calculations.


Final Thoughts

Many Oracle Payroll implementations spend considerable effort recreating time calculation logic that already exists in external workforce management applications.

The PayrollTimeCard HDL business object provides a simpler alternative.

If your external system is already producing approved payroll-ready time transactions, consider loading the final results directly into Oracle Payroll rather than duplicating complex rules inside Oracle.

Used correctly, PayrollTimeCard HDL can simplify integrations, reduce maintenance effort, and streamline payroll processing while maintaining a clear audit trail between the source time system and Oracle Payroll.

Friday, 12 June 2026

Oracle Cloud Payroll: Creating Element Entries with Costing Using HDL

Oracle Cloud Payroll: Creating Element Entries with Costing Using HDL

Introduction

Most Oracle Cloud Payroll implementations use HCM Data Loader (HDL) extensively to create and maintain element entries. Common use cases include:

  • Bonus payments
  • One-time earnings
  • Allowances
  • Deduction entries
  • Retro adjustments
  • Conversion data
  • Payroll parallel run data

However, one requirement that often surprises implementation teams is:

How do we create an element entry and simultaneously override its costing information using HDL?

Many payroll teams initially assume this requires a separate costing process, manual maintenance, or payroll costing override after the element entry is created.

Fortunately, Oracle Cloud HCM Data Loader provides support for creating element entries together with costing information using the ElementEntryWithCosting business object.

This is particularly useful for bonus payments, project-based earnings, special allocations, payroll adjustments, and conversion activities where the payroll cost must be charged to a specific cost center or accounting segment.


Business Requirement

Consider a common scenario. An employee receives a one-time bonus payment of $100.

Normally, the employee's payroll costs are charged to their home department:

100100

However, for this bonus payment, Finance wants the expense charged to a different cost center:

020000

Instead of creating the element entry first and then manually overriding costing, both the element entry and costing override can be loaded together through HDL.


HDL Business Object

For this requirement, Oracle provides the following HDL business object:

ElementEntryWithCosting

This business object allows you to load the following in a single HDL file:

  • Element entry
  • Input values
  • Costing segment overrides

Sample HDL

The following example creates a Bonus Pay element entry and overrides Costing Segment 2.

METADATA|ElementEntryWithCosting|AssignmentNumber|ElementName|EntryType|CreateEntrySequence|EffectiveStartDate|EffectiveEndDate|InputValueName1|ScreenEntryValue1|Segment2
MERGE|ElementEntryWithCosting|E10|Bonus Pay|E|1|2026/06/10|4712/12/31|Amount|100|020000

Understanding the HDL

AssignmentNumber

E10

Identifies the employee assignment that will receive the element entry.

ElementName

Bonus Pay

Identifies the payroll element being created.

EntryType

E

Indicates a standard element entry.

CreateEntrySequence

1

Used when multiple entries may exist for the same element.

Effective Dates

2026/06/10
4712/12/31

Defines the effective period of the element entry.

Input Value

InputValueName1 = Amount
ScreenEntryValue1 = 100

Creates the element entry with an Amount input value of $100.

Costing Override

Segment2 = 020000

Overrides Costing Segment 2 for this specific element entry.

This allows payroll costs generated by this element to be charged to a different accounting segment than the employee's default costing.


Result After HDL Load

After the HDL load, the following element entry is created:

Assignment: E10
Element: Bonus Pay
Amount: 100

The costing override is also created:

Segment2 = 020000

During payroll processing, the resulting payroll costs will use the overridden costing segment for this specific element entry.








Typical Use Cases

Bonus Allocations

Charge annual, spot, or special bonuses to a specific project, department, or cost center.

Project-Based Earnings

Allocate payroll costs to customer-funded projects or special business initiatives.

Grant Accounting

Override costing for grant-funded employees or grant-funded payments.

Payroll Adjustments

Direct payroll adjustment costs to a specific accounting combination.

Payroll Conversion Activities

Load historical element entries with corresponding costing distributions during implementation or parallel payroll validation.


Important Feature: Rollback HDL Load

One very useful feature when using ElementEntryWithCosting HDL is the ability to roll back the HDL load if something goes wrong.

This is especially helpful because you do not need to prepare a separate delete HDL file manually.

For example, if the element entry or costing segment was loaded incorrectly, you can use the HDL rollback option to reverse the HDL load, correct the source file, and reload the data.

This simplifies testing and production support because:

  • Incorrect HDL loads can be reversed more easily
  • No separate delete file is required
  • Testing multiple scenarios becomes faster
  • Payroll teams can recover from load errors more efficiently
  • Auditability is preserved through the HDL process

This is very useful during:

  • Payroll conversion
  • Bonus load testing
  • Costing override testing
  • One-time payment loads
  • Parallel payroll validation

Practical Recommendation

When loading element entries with costing, always keep track of the HDL batch name and import process ID. This makes it easier to identify and roll back the correct HDL load if needed.





Important Considerations

Costing Flexfield Structure

The available HDL costing segments depend on your costing key flexfield configuration.

Examples may include:

Segment1
Segment2
Segment3
Segment4
Segment5

or additional segments depending on your chart of accounts.

Costing Validation

The segment values provided through HDL must exist as valid values in the chart of accounts.

Invalid values will cause HDL validation failures.

Testing

Always validate the following before moving the process into production:

  • HDL load success
  • Element entry creation
  • Costing override creation
  • Payroll run results
  • Payroll costing results
  • Transfer to General Ledger

Why This Matters

Many payroll implementations require occasional costing overrides but continue to rely on manual updates after element creation.

Using ElementEntryWithCosting allows organizations to automate both the payroll transaction and its costing treatment in a single HDL load.

This reduces manual effort, improves auditability, and creates a cleaner operational process for payroll and finance teams.

For payroll conversion projects, bonus interfaces, project-based compensation, and financial allocations, this capability can significantly simplify the solution design.


Final Thoughts

Oracle HDL provides several payroll-specific business objects that are often overlooked because most examples focus only on creating basic element entries.

The ElementEntryWithCosting business object is one of those hidden gems.

If your requirement involves creating payroll element entries and directing the resulting payroll costs to a specific accounting segment, consider using this object instead of relying on manual costing updates after the fact.

A small HDL enhancement can eliminate significant operational effort and provide a cleaner, more controlled payroll process.

Thursday, 21 May 2026

Oracle HCM Extract Best Practice: Draft vs Final Vendor Delivery Using Report Category

Oracle HCM Extract Best Practice: Draft vs Final Vendor Delivery Using Report Category

Introduction

One of the most common operational requirements in Oracle Cloud HCM and Payroll integrations is not just generating outbound vendor files—but controlling when those files are transmitted.

Typical outbound integrations include files sent to:

  • Benefits providers
  • Retirement vendors
  • Garnishment agencies
  • Payroll banking partners
  • Insurance carriers
  • Tax agencies
  • External payroll processors

A very common business requirement looks like this:

Run the HCM Extract → Validate the output → If the results look correct, send the file to the vendor via SFTP

At first glance, teams often assume this requires:

  • Custom orchestration
  • Middleware intervention
  • Manual file download/upload
  • Duplicate extract definitions
  • Custom ESS job chains

However, Oracle HCM Extract provides a standard capability that is often underutilized:

Report Category

This standard parameter allows implementation teams to control extract delivery behavior by associating different delivery configurations with different report categories.

With the right design, this provides a clean way to separate file generation from vendor transmission, without unnecessary customization.


The Common Business Problem

In many payroll and HCM outbound integrations, sending the file immediately after extract generation is not always desirable.

Examples include:

Payroll Vendor Files

A payroll deduction remittance file may require payroll or finance validation before transmission.

Benefits Enrollment Files

Benefit carrier enrollment files may need operational verification before delivery.

Garnishment Files

Incorrect transmission may create compliance or payment issues.

Tax Reporting Files

Organizations may require internal review before sending statutory reporting files externally.

In all these scenarios, the desired operational process becomes:

  1. Generate file
  2. Review output
  3. Approve for release
  4. Deliver to vendor

The challenge is enabling this process without introducing unnecessary architectural complexity.


Common, But Often Overengineered, Approaches

To solve this requirement, teams often consider:

  • Creating separate draft and production extracts
  • Middleware orchestration logic
  • Manual download and upload processes
  • Custom ESS scheduling chains
  • External SFTP automation scripts

While these approaches can work, they often add complexity that may not be necessary.


The Standard Oracle Solution: Report Category

Oracle HCM Extract includes a standard parameter called:

Report Category

This parameter can be used to group and control extract delivery behavior.

Instead of treating delivery as a fixed part of extract execution, you can design multiple operational modes using report categories.

This becomes especially useful when outbound vendor files require business validation before release.


Practical Design Pattern: Draft vs Final

In this implementation approach, the same HCM Extract is configured with two report categories:

  • Draft
  • Final

Each category supports a different operational outcome. You can create any number of report categories and name them as per your needs.


Option 1: Draft

The Draft report category generates the file but keeps it internally accessible within Oracle/UCM without transmitting it externally.

Flow:

Run Extract (Draft)
→ File Generated
→ Payroll / HR Reviews Output
→ Business Approval

In this example, the Draft report category has one delivery option configured under it.




Option 2: Final

Once the draft output is validated, the same extract is rerun using the Final report category.

In this mode, the configured delivery options, such as SFTP, are executed.

Flow:

Run Extract (Final)
→ File Generated
→ Automatically Delivered via SFTP

This provides a clean operational promotion model from review to release.




Important Design Consideration

Since the extract is rerun in Final mode, organizations should ensure the underlying source data remains unchanged between Draft validation and Final transmission.

For payroll integrations, this typically means ensuring:

  • Payroll results are finalized
  • No retro changes occur between validation and transmission
  • No operational changes impact extract data between runs

This avoids validating one dataset and transmitting another.


Real-World Payroll Example

Consider a 401(k)-deduction remittance file.

Business requirement:

  • Generate deduction file after payroll
  • Payroll team validates totals
  • Confirm deduction balances match payroll register
  • Only then transmit to Fidelity (vendor)

Without delivery control:

  • File may be transmitted immediately
  • Errors become vendor-facing operational incidents
  • Corrections require rework and vendor coordination

With the Draft/Final report category approach:

Draft

  • File generated
  • Payroll validates totals
  • Internal signoff obtained

Final

  • Same extract reruns
  • Approved file transmitted via SFTP

This creates a much cleaner operational model.







Why This Matters

This is not just a technical extract parameter.

This approach improves:

Operational Control

Prevents premature vendor transmission.

Error Prevention

Catches extract issues before they become external incidents.

Compliance Support

Useful for regulated outbound integrations.

Simplified Design

Avoids unnecessary middleware or duplicate solutions.

Supportability

Gives operations teams a predictable and manageable process.


Where This Pattern Works Well

This approach works especially well for:

  • Payroll deduction remittance files
  • Retirement contribution vendor files
  • Benefit carrier interfaces
  • Garnishment remittance files
  • Tax reporting interfaces
  • Banking/payment outbound files
  • Third-party payroll vendor integrations

Practical Recommendation

For outbound vendor integrations, ask a simple question:

Should this file be transmitted immediately, or should the business validate first?

If validation is required, consider using Report Category strategically before introducing custom orchestration.


When This May Not Be Enough

While this pattern works well for many use cases, more complex scenarios may still require additional design considerations.

Examples include:

  • Conditional routing to different vendors
  • Multiple simultaneous delivery destinations
  • Dynamic file naming rules
  • Complex orchestration dependencies
  • Approval workflows requiring system-enforced gating

In these cases, middleware or additional automation may still be appropriate.


Final Thoughts

Oracle often provides standard capabilities that solve practical implementation problems without customization.

Report Category in HCM Extract is one of those underused features.

If your operational requirement is:

Generate → Validate → Then Send

Do not immediately assume middleware or custom orchestration is required.

A simple Draft vs Final Report Category design may provide exactly the operational control your business needs—with far less complexity.

Wednesday, 13 May 2026

Oracle Payroll Integration with UKG: Calculation Card vs Element Entry — Understanding the Correct HDL Object

Oracle Payroll Integration with UKG: Calculation Card vs Element Entry — Understanding the Correct HDL Object

Introduction

When integrating UKG, or any external time system, with Oracle Cloud HCM Payroll, a common design question is:

Should time be loaded as Element Entries, or should we use PayrollTimeCard / PayrollAbsenceRecord HDL objects?

This blog clarifies the relationship between PayrollTimeCard.dat, PayrollAbsenceRecord.dat, ElementEntry.dat, and Calculation Cards, and explains the recommended design approach for Oracle Payroll integrations.


The Core Design Decision

There are two primary integration patterns for third-party time and absence data:

  1. PayrollTimeCard.dat / PayrollAbsenceRecord.dat — time/absence-driven model
  2. ElementEntry.dat — payroll-result-driven model

Calculation Cards should not be treated as a separate third option. They are the payroll representation layer where time and absence data may appear after being loaded through the correct business objects.


Key Clarification: Calculation Cards Are the Target Representation

The most important clarification is:

PayrollTimeCard.dat and PayrollAbsenceRecord.dat both populate Calculation Cards, but you should not use CalculationCard.dat directly to load time or absence data.

In other words, Oracle may create or update Calculation Cards as part of the payroll time or absence load process, but the integration should use the purpose-built HDL objects.

What This Means in Practice

  • PayrollTimeCard.dat creates or updates Calculation Cards with time entries.
  • PayrollAbsenceRecord.dat creates or updates Calculation Entries for absences.
  • CalculationCard.dat should not be used for time or absence integration.

How Oracle Designed This

Oracle separates the object you load from where the data appears in payroll.

HDL Object Purpose Where Data Appears
PayrollTimeCard.dat Time-card data Calculation Cards / Calculation Entries
PayrollAbsenceRecord.dat Absence data Calculation Entries
ElementEntry.dat Payroll-ready inputs Element Entries
CalculationCard.dat Generic calculation card object Not recommended for time/absence loading

Pattern 1: PayrollTimeCard.dat — Recommended for Time

When to Use

Use PayrollTimeCard.dat when UKG is the system of record for approved time, but Oracle Payroll still needs to process the time data.

This approach is useful when Oracle Payroll needs to:

  • Calculate overtime
  • Apply premiums
  • Handle costing
  • Apply jurisdiction-specific payroll logic
  • Preserve work-date level detail

What Happens

  1. UKG sends approved time-card data.
  2. PayrollTimeCard.dat is loaded.
  3. Oracle validates the time-card elements.
  4. Oracle creates or updates Calculation Cards.
  5. Payroll processes the time entries.

Pattern 2: PayrollAbsenceRecord.dat — Recommended for Absences

When to Use

Use AbsenceEntry.dat when UKG or another external system sends approved absence data and you want Oracle Payroll to process absence-related payroll logic.

What Happens

  • Absence records are loaded using PayrollAbsenceRecord.dat.
  • Oracle creates the related calculation entries.
  • Payroll processes the absence-related elements.

Pattern 3: ElementEntry.dat — Payroll-Ready Inputs

When to Use

Use ElementEntry.dat when UKG has already calculated the payroll values and Oracle Payroll only needs to consume the final results.

This may include:

  • Regular pay
  • Overtime
  • Premiums
  • Adjustments
  • Payroll-ready hours or amounts

This pattern can be simpler, but it places more responsibility on the integration for validation, correction handling, duplicate prevention, and reconciliation.


Why Not Use CalculationCard.dat?

Although PayrollTimeCard.dat and PayrollAbsenceRecord.dat populate Calculation Cards, you should not use CalculationCard.dat directly for time or absence loads.

Using CalculationCard.dat for time or absence can create issues because:

  • It bypasses purpose-built validation logic.
  • It does not align with Oracle’s recommended payroll data model.
  • It can make reconciliation and maintenance more difficult.

The Real Relationship

The correct way to think about this is:

PayrollTimeCard.dat and PayrollAbsenceRecord.dat are calculation-card-based integrations, but they are implemented through specialized business objects, not through CalculationCard.dat.


Benefits of PayrollTimeCard.dat and PayrollAbsenceRecord.dat

1. Data Model Alignment

  • Matches Oracle Payroll architecture
  • Preserves time and absence granularity

2. Built-In Validation

  • Supports element eligibility validation
  • Provides structured error handling

3. Better Reconciliation

  • Aligns source system data with payroll processing
  • Supports audit at a detailed level

Challenges to Plan For

1. Source Key Strategy

A strong source key strategy is required for updates, corrections, and reconciliation.

2. Correction Model

Corrections should generally be made in the source system and re-imported, rather than manually adjusted in payroll.

3. Visibility

  • Data appears in Calculation Cards.
  • It does not appear in Oracle Time and Labor time cards.

4. Setup Requirements

The design requires proper configuration of:

  • Payroll elements
  • Element eligibility
  • Related generated elements where applicable

Practical Recommendation

Use PayrollTimeCard.dat when:

  • You want time-driven payroll processing.
  • You need detailed audit and reconciliation.
  • You want Oracle Payroll to process time-card-style data.

Use PayrollAbsenceRecord.dat when:

  • You are integrating approved absence data.
  • You want Oracle Payroll to process absence-related payroll logic.

Use ElementEntry.dat when:

  • You receive payroll-ready values from UKG.
  • UKG has already calculated the final payable hours or amounts.

Avoid:

  • Using CalculationCard.dat directly for time or absence data.

Conclusion

The confusion around Calculation Cards usually comes from treating them as an integration option rather than understanding what they represent.

Calculation Cards are the internal payroll representation of time and absence data, but the correct load mechanism is through the appropriate HDL business object.

Final Takeaway

  • PayrollTimeCard.dat and PayrollAbsenceRecord.dat do populate Calculation Cards.
  • You should not use CalculationCard.dat directly for time or absence loads.
  • ElementEntry.dat remains valid for payroll-ready inputs.

Using the correct HDL object ensures that the integration is aligned with Oracle’s payroll architecture, easier to reconcile, and more scalable for long-term maintenance.

Monday, 23 March 2026

Loading Oracle Cloud Time and Labor Time Entries via REST API using PL/SQL (UTL_HTTP)

Loading Oracle Cloud Time and Labor Time Entries via REST API using PL/SQL (UTL_HTTP)

Oracle Cloud HCM Time and Labor integrations are commonly built using Python, OCI Integration, or other middleware tools. However, there are situations where a lightweight, database-driven approach is useful, especially for rapid prototyping, controlled batch processing, or small-volume integrations.

In this example, the REST API is invoked directly from a local Oracle Express Edition database running on a personal system. The solution uses a custom staging table, PL/SQL procedures, UTL_HTTP, and an Oracle wallet for secure HTTPS communication. The example focuses on loading time entries through the REST API flow and not a separate time event integration model.

Important Note: This REST API supports creation of complete time entries that include both start time and stop time (or measured duration). It leverages the same configuration used for standard time entry in Oracle Time and Labor and does not require any additional setup.

However, if the business requirement involves capturing partial time events (such as only start time or only stop time), a different REST endpoint (/hcmRestApi/resources/11.13.18.05/timeRecordEventRequests/) must be used. This approach requires additional configurations, including event definitions and device-related attributes.

This approach is particularly useful for

  • One time – time entries load for payroll parallel run testing, time parallel run testing
  • Rapid prototyping
  • Small-scale integrations
  • Controlled batch processing from staging tables
  • Enter the time entries in custom application/UI and then load into OTL with more controlled way.

Solution Overview

The design follows a simple but effective pattern:

  1. Insert time entry records into a custom staging table.
  2. Read unprocessed rows from the staging table.
  3. Construct the REST payload in PL/SQL.
  4. Call Oracle Cloud HCM REST API using UTL_HTTP.
  5. Capture response details and update the processing status.

Step 1: Create the staging table

The staging table stores inbound time entry data and maintains processing metadata such as status, request identifiers, API response, and error message.

CREATE TABLE xx_time_entry_stg (
    id                     NUMBER GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY,
    reporter_id            VARCHAR2(100)   NOT NULL,
    start_time             VARCHAR2(50)    NOT NULL,
    stop_time              VARCHAR2(50)    NOT NULL,
    payroll_time_type      VARCHAR2(200)   NOT NULL,
    comment_txt            VARCHAR2(1000),
    process_status         VARCHAR2(30)    DEFAULT 'NEW',
    request_id             NUMBER,
    event_id               NUMBER,
    response_clob          CLOB,
    error_message          VARCHAR2(4000),
    created_on             DATE            DEFAULT SYSDATE,
    updated_on             DATE
);

This structure provides a strong foundation for traceability and troubleshooting:

  • process_status tracks whether a row is NEW, PROCESSING, SUCCESS, or ERROR.
  • response_clob stores the full REST API response for audit and debugging.
  • error_message stores a summarized failure reason.
  • request_id and event_id help connect the database record to the HCM transaction.

Step 2: Insert sample time entry data

A sample record can be inserted into the staging table before processing.In this example we are using 4 days’ time entries for 1 employee.

INSERT INTO xx_time_entry_stg (
    reporter_id,
    start_time,
    stop_time,
    payroll_time_type,
    comment_txt
) VALUES (
    '1129',
    '2026-03-16T08:00:00.000-04:00',
    '2026-03-16T17:00:00.000-04:00',
    'XX Regular Hours US',
    'Loaded from custom table-1'
);
INSERT INTO xx_time_entry_stg (
    reporter_id,
    start_time,
    stop_time,
    payroll_time_type,
    comment_txt
) VALUES (
    '1129',
    '2026-03-17T08:00:00.000-04:00',
    '2026-03-17T17:00:00.000-04:00',
    'XX Regular Hours US',
    'Loaded from custom table-1'
);
INSERT INTO xx_time_entry_stg (
    reporter_id,
    start_time,
    stop_time,
    payroll_time_type,
    comment_txt
) VALUES (
    '1129',
    '2026-03-18T08:00:00.000-04:00',
    '2026-03-18T17:00:00.000-04:00',
    'XX Regular Hours US',
    'Loaded from custom table-1'
);
INSERT INTO xx_time_entry_stg (
    reporter_id,
    start_time,
    stop_time,
    payroll_time_type,
    comment_txt
) VALUES (
    '1129',
    '2026-03-19T08:00:00.000-04:00',
    '2026-03-19T17:00:00.000-04:00',
    'XX Regular Hours US',
    'Loaded from custom table-1'
);
COMMIT;

The timestamp values are provided in ISO 8601 format with timezone offset, which is important for Oracle Cloud HCM REST requests.

Step 3: Build the PL/SQL procedure that loads one time entry

The main procedure reads a staging row, constructs the JSON payload, invokes the REST API, reads the response, and updates the row status.

CREATE OR REPLACE PROCEDURE xx_load_one_time_entry (
    p_id                IN NUMBER,
    p_host              IN VARCHAR2,
    p_username          IN VARCHAR2,
    p_password          IN VARCHAR2,
    p_wallet_path       IN VARCHAR2,
    p_wallet_password   IN VARCHAR2
) AS
    l_url              VARCHAR2(2000);
    l_req              UTL_HTTP.req;
    l_resp             UTL_HTTP.resp;
    l_buffer           VARCHAR2(32767);
    l_response_clob    CLOB;
    l_payload          CLOB;

    l_reporter_id      xx_time_entry_stg.reporter_id%TYPE;
    l_start_time       xx_time_entry_stg.start_time%TYPE;
    l_stop_time        xx_time_entry_stg.stop_time%TYPE;
    l_payroll_type     xx_time_entry_stg.payroll_time_type%TYPE;
    l_comment_txt      xx_time_entry_stg.comment_txt%TYPE;

    l_request_id       NUMBER;
    l_event_id         NUMBER;
    l_event_status     VARCHAR2(100);
    l_status_code      PLS_INTEGER;
    l_reason_phrase    VARCHAR2(256);
    l_error_message    VARCHAR2(4000);
BEGIN
    SELECT reporter_id,
           start_time,
           stop_time,
           payroll_time_type,
           NVL(comment_txt, 'Loaded from custom table')
    INTO   l_reporter_id,
           l_start_time,
           l_stop_time,
           l_payroll_type,
           l_comment_txt
    FROM   xx_time_entry_stg
    WHERE  id = p_id
    FOR UPDATE;

    UPDATE xx_time_entry_stg
       SET process_status = 'PROCESSING',
           updated_on     = SYSDATE,
           error_message  = NULL
     WHERE id = p_id;

    l_url := 'https://' || p_host || '/hcmRestApi/resources/11.13.18.05/timeRecordEventRequests';

    l_payload :=
           '{'
        || '\"processInline\":\"Y\",'
        || '\"processMode\":\"TIME_SAVE\",'
        || '\"timeRecordEvent\":['
        ||   '{'
        ||     '\"startTime\":\"' || REPLACE(REPLACE(l_start_time, '\', '\\'), '\"', '\\\"') || '\",'
        ||     '\"stopTime\":\"' || REPLACE(REPLACE(l_stop_time, '\', '\\'), '\"', '\\\"') || '\",'
        ||     '\"reporterIdType\":\"PERSON\",'
        ||     '\"reporterId\":\"' || REPLACE(REPLACE(l_reporter_id, '\', '\\'), '\"', '\\\"') || '\",'
        ||     '\"comment\":\"' || REPLACE(REPLACE(l_comment_txt, '\', '\\'), '\"', '\\\"') || '\",'
        ||     '\"operationType\":\"ADD\",'
        ||     '\"timeRecordEventAttribute\":['
        ||       '{'
        ||         '\"attributeName\":\"PayrollTimeType\",'
        ||         '\"attributeValue\":\"' || REPLACE(REPLACE(l_payroll_type, '\', '\\'), '\"', '\\\"') || '\"'
        ||       '}'
        ||     ']'
        ||   '}'
        || ']'
        || '}';

    UTL_HTTP.set_detailed_excp_support(TRUE);
    UTL_HTTP.set_response_error_check(FALSE);
    UTL_HTTP.set_wallet(p_wallet_path, p_wallet_password);

    l_req := UTL_HTTP.begin_request(l_url, 'POST', 'HTTP/1.1');

    UTL_HTTP.set_authentication(l_req, p_username, p_password, 'Basic', FALSE);
    UTL_HTTP.set_header(l_req, 'Content-Type', 'application/json');
    UTL_HTTP.set_header(l_req, 'Accept', 'application/json');
    UTL_HTTP.set_header(l_req, 'Content-Length', TO_CHAR(DBMS_LOB.getlength(l_payload)));
    UTL_HTTP.write_text(l_req, l_payload);

    l_resp := UTL_HTTP.get_response(l_req);
    l_status_code   := l_resp.status_code;
    l_reason_phrase := l_resp.reason_phrase;

    DBMS_LOB.createtemporary(l_response_clob, TRUE);

    BEGIN
        LOOP
            UTL_HTTP.read_text(l_resp, l_buffer, 32767);
            DBMS_LOB.writeappend(l_response_clob, LENGTH(l_buffer), l_buffer);
        END LOOP;
    EXCEPTION
        WHEN UTL_HTTP.end_of_body THEN
            NULL;
    END;

    UTL_HTTP.end_response(l_resp);

    BEGIN
        SELECT JSON_VALUE(l_response_clob, '$.timeRecordEventRequestId' RETURNING NUMBER),
               JSON_VALUE(l_response_clob, '$.timeRecordEvent[0].timeRecordEventId' RETURNING NUMBER),
               JSON_VALUE(l_response_clob, '$.timeRecordEvent[0].eventStatus' RETURNING VARCHAR2(100))
          INTO l_request_id, l_event_id, l_event_status
          FROM dual;
    EXCEPTION
        WHEN OTHERS THEN
            l_request_id   := NULL;
            l_event_id     := NULL;
            l_event_status := NULL;
    END;

    IF l_status_code BETWEEN 200 AND 299
       AND l_event_status = 'COMPLETE'
    THEN
        UPDATE xx_time_entry_stg
           SET process_status = 'SUCCESS',
               request_id     = l_request_id,
               event_id       = l_event_id,
               response_clob  = l_response_clob,
               updated_on     = SYSDATE,
               error_message  = NULL
         WHERE id = p_id;
    ELSE
        l_error_message :=
            SUBSTR(
                'HTTP ' || l_status_code || ' ' || l_reason_phrase || ' | ' ||
                DBMS_LOB.SUBSTR(l_response_clob, 3000, 1),
                1,
                4000
            );

        UPDATE xx_time_entry_stg
           SET process_status = 'ERROR',
               request_id     = l_request_id,
               event_id       = l_event_id,
               response_clob  = l_response_clob,
               updated_on     = SYSDATE,
               error_message  = l_error_message
         WHERE id = p_id;
    END IF;

    COMMIT;

EXCEPTION
    WHEN OTHERS THEN
        BEGIN
            UTL_HTTP.end_response(l_resp);
        EXCEPTION
            WHEN OTHERS THEN
                NULL;
        END;

        l_error_message :=
            SUBSTR(
                SQLERRM || ' | ' || UTL_HTTP.get_detailed_sqlerrm,
                1,
                4000
            );

        UPDATE xx_time_entry_stg
           SET process_status = 'ERROR',
               updated_on     = SYSDATE,
               error_message  = l_error_message
         WHERE id = p_id;

        COMMIT;
        RAISE;
END;
/

How the procedure works

  • It selects a specific staging row by ID and locks it using FOR UPDATE.
  • It updates the row to PROCESSING before the API call starts.
  • It constructs the JSON payload dynamically in PL/SQL.
  • It uses UTL_HTTP to send the HTTPS POST request.
  • It reads the REST response into a CLOB.
  • It parses the response using JSON_VALUE.
  • It marks the row as SUCCESS only when the HTTP status is successful and the returned event status is COMPLETE.
  • Otherwise, it stores the failure details and marks the record as ERROR.

REST payload design

The payload uses processInline = "Y" and processMode = "TIME_SAVE". This is important because the integration is being used to save a time entry through the REST API processing flow. You can change processMode = "TIME_SUBMIT"or "TIME_ENTER" depending on your requirement. The payload also passes:

  • startTime - start time of the time entry
  • stopTime - stop time of the time entry
  • reporterIdType - PERSON
  • reporterId - Person Number
  • comment - any custom optional comment
  • operationType - ADD
  • PayrollTimeType - Time type defined in the layout component set(element name not the display name)

This makes the example practical for a common Time and Labor requirement where the integration needs to create a time entry with a payroll time type.

Important implementation details

1. Wallet configuration for HTTPS

The call uses UTL_HTTP.set_wallet so the local Oracle database can trust the SSL certificate presented by Oracle Cloud. Without a properly configured wallet, HTTPS requests typically fail.

2. Content-Length header

The code explicitly sets the Content-Length header using DBMS_LOB.getlength(l_payload). This is a very important detail because missing this header can result in HTTP 411 Length Required errors.

3. JSON escaping

The code carefully escapes backslashes and double quotes when building the payload. This is important because comments and other text values can break the JSON structure if they are not escaped correctly.

4. Detailed exception support

UTL_HTTP.set_detailed_excp_support(TRUE) makes troubleshooting easier by exposing more detailed network and HTTP diagnostics.

5. Response parsing

The API response is stored in a CLOB and parsed for:

  • timeRecordEventRequestId
  • timeRecordEventId
  • eventStatus

This gives the solution both technical traceability and business-level visibility into the outcome.

Step 4: Batch procedure for multiple entries

To process all new staging rows, a batch procedure loops through records with status NEW and calls the single-row loader for each entry.

CREATE OR REPLACE PROCEDURE xx_load_time_entries_batch (
    p_host              IN VARCHAR2,
    p_username          IN VARCHAR2,
    p_password          IN VARCHAR2,
    p_wallet_path       IN VARCHAR2,
    p_wallet_password   IN VARCHAR2
) AS
BEGIN
    FOR r IN (
        SELECT id
        FROM xx_time_entry_stg
        WHERE process_status = 'NEW'
        ORDER BY id
    ) LOOP
        BEGIN
            xx_load_one_time_entry(
                p_id              => r.id,
                p_host            => p_host,
                p_username        => p_username,
                p_password        => p_password,
                p_wallet_path     => p_wallet_path,
                p_wallet_password => p_wallet_password
            );
        EXCEPTION
            WHEN OTHERS THEN
                NULL;
        END;
    END LOOP;
END;
/

This design keeps the processing model simple. Each row is handled independently, which makes error isolation easier. One failed row does not stop the remaining rows from being attempted.

Step 5: Execute the batch load

The batch procedure can be executed with the Oracle Cloud host, credentials, and wallet details.

BEGIN
    xx_load_time_entries_batch(
        p_host            => 'your-test-instance.fa.us6.oraclecloud.com',
        p_username        => 'your_username',
        p_password        => 'your_password',
        p_wallet_path     => 'file:c:\wallet',
        p_wallet_password => 'your_wallet_password'
    );
END;
/

After execution, the staging table can be queried to confirm whether each record completed successfully or failed with an error.

SELECT *
FROM xx_time_entry_stg
ORDER BY id;

Testing the solution

A good test cycle for this approach is:

  1. Record inserted in staging table
  2. Run the batch procedure
  3. Status transitions:
    • NEW → PROCESSING → SUCCESS / ERROR
  4. Response captured in response_clob
  5. Review the failed records if any
  6. Validate time entries from the front-end(You don’t have to run any job/any scheduled process to see the entries in the front-end)



This gives a clean and repeatable way to validate the integration end to end.

Common issues and troubleshooting

Issue Possible Cause Typical Fix
ORA-29273 HTTP request failed Check wallet setup, ACLs, hostname, SSL trust, and network connectivity
ORA-28759 Failure to open wallet file Verify wallet path, database service account permissions, and wallet contents
HTTP 411 Length Required Missing Content-Length header Explicitly set Content-Length before writing the payload
Invalid JSON or API rejection Malformed payload or unescaped text Escape values correctly and validate the payload structure

Strengths of this pattern

  • Simple and easy to understand
  • Fully database-driven
  • Good audit trail through staging and stored responses
  • Useful for low-volume or controlled integrations
  • No separate middleware is required for the basic flow

Practical limitations

  • It is not the best pattern for very high transaction volumes.
  • Basic authentication may not be the preferred production-grade option in all environments.
  • Sequential row-by-row processing can become a bottleneck at scale.
  • Credential handling must be hardened before production use.

Recommendations for production hardening

  • Move credentials out of anonymous execution blocks and store them securely.
  • Add a retry strategy for transient failures.
  • Introduce better logging for request payloads, response codes, and execution timestamps.
  • Add validation logic before calling the REST API.
  • Consider parallel processing for larger data volumes.
  • Review whether OAuth-based authentication is required in the target environment.

Key takeaway

This example shows how Oracle Database can act as a lightweight integration layer for Oracle Cloud HCM Time and Labor. By combining a staging table, PL/SQL, UTL_HTTP, and wallet-based HTTPS configuration, it is possible to load time entries directly from a local Oracle XE environment while still preserving auditability and control.

For teams that want a compact and database-centric integration option, this is a practical pattern worth considering.

Disclaimer

This example is intended for demonstration and learning purposes. Additional controls, security hardening, validation, and operational considerations may be required before adopting the pattern in a production environment.

Thursday, 28 January 2021

SQL Query to Get Database Items and context

 SELECT DBI.USER_NAME,BASE_CONTEXT_NAME

FROM FF_DATABASE_ITEMS_VL DBI,

FF_USER_ENTITIES_VL USERENT,

FF_ROUTES_VL ROUTES,

FF_ROUTE_CONTEXT_USAGES RCU,

FF_CONTEXTS_VL CON

Where  DBI.USER_ENTITY_ID = USERENT.USER_ENTITY_ID

AND USERENT.ROUTE_ID = ROUTES.ROUTE_ID

AND DBI.base_USER_name = <DBI Name>

AND ROUTES.ROUTE_ID = RCU.ROUTE_ID

AND CON.CONTEXT_ID = RCU.CONTEXT_ID

==========================================================

select FF.FORMULA_NAME, BASE_CONTEXT_NAME

ff_contexts_vl CON,

ff_ftype_context_usages FCU,

FF_FORMULA_TYPES_VL FT

WHERE FF.formula_type_id = FT.formula_type_id

AND   FCU.FORMULA_TYPE_ID =  FT.formula_type_id

AND   CON.CONTEXT_ID = FCU.CONTEXT_ID

AND   BASE_FORMULA_NAME LIKE <Formula Bas Name>

Wednesday, 24 January 2018

Payroll Batch Loader Error Query



select ml.*
from pay_bl_message_lines_vl ml
,    pay_batch_lines bl
,    pay_batch_headers bh
where bh.batch_id = bl.batch_id
and   bl.batch_line_id = ml.source_id
and   bh.batch_name = 'BATCH NAME'
and   bl.batch_line_status = 'E';


Full Query for all PBL errors with batch name, task name, task action name, assignment number and error message


SELECT pbh.batch_name,
       pbh.legislative_data_group_id,pbt.display_task_name,pbta.display_task_action_name,
pivot_line_value_data.action_parameter_name1,pivot_line_value_data.action_parameter_value1,pivot_line_value_data.action_parameter_name2,pivot_line_value_data.action_parameter_value2,
       pbmlv.message_text
FROM
(SELECT batch_line_id,
     MAX(decode(rn,1,display_action_parameter_name))
action_parameter_name1,MAX(decode(rn,1,action_parameter_value))
action_parameter_value1,
     MAX(decode(rn,2,display_action_parameter_name))
action_parameter_name2,MAX(decode(rn,2,action_parameter_value))
action_parameter_value2,
     MAX(decode(rn,3,display_action_parameter_name))
action_parameter_name3,MAX(decode(rn,3,action_parameter_value))
action_parameter_value3,
    MAX(decode(rn,4,display_action_parameter_name))
action_parameter_name4,MAX(decode(rn,4,action_parameter_value))
action_parameter_value4
 FROM ( SELECT batch_line_id,
               action_parameter_name,
       action_parameter_value,
       display_action_parameter_name,
               row_number() over (partition by batch_line_id
                          order by batch_line_id,
  action_parameter_name ) rn
          FROM (SELECT pbavl.element_name action_parameter_name,
               pbavl.parameter_name display_action_parameter_name,
       pblv.action_parameter_value,
       pblv.batch_line_id
FROM pay_task_parameters_vl pbavl,  pay_batch_line_values pblv
WHERE pbavl.base_task_parameter_id = pblv.action_parameter_id
AND pbavl.display_flag <> 'N' ) 
          )
GROUP BY batch_line_id) pivot_line_value_data,
                        pay_batch_lines pbl ,
                  pay_batch_headers pbh,
                        pay_bl_message_lines_vl pbmlv,
PAY_BL_TASK_ACTIONS_VL pbta,PAY_BL_TASKS_VL pbt
WHERE pivot_line_value_data.batch_line_id = pbl.batch_line_id
AND pbl.batch_id = pbh.batch_id
AND pbl.batch_line_id = pbmlv.source_id
AND pbl.batch_line_status = 'E'
AND pbh.batch_name like '%Pay%%%'
AND pbt.task_id=pbta.task_id
and pbl.task_action_id=pbta.task_action_id