# Customized Objects Inventory

LLMS index: [llms.txt](/llms.txt)

---

<div id="pslens-context-panel" class="card border-info mb-4 d-none">
  <div class="card-header bg-light text-info py-2 fw-bold d-flex align-items-center border-bottom border-info-subtle">
    <i class="bi bi-info-circle-fill me-2"></i>
    <span>Tailored Operational Context</span>
  </div>
  <div class="card-body p-0">
    <ul class="list-group list-group-flush">
      <li id="row-db" class="list-group-item d-flex align-items-center justify-content-between py-2 d-none">
        <strong>Target Database:</strong>
        <span id="ctx-db" class="badge bg-secondary font-monospace">&mdash;</span>
      </li>
      <li id="row-type" class="list-group-item d-flex align-items-center justify-content-between py-2 d-none">
        <strong>Context Type:</strong>
        <span id="ctx-type" class="badge bg-light text-dark border font-monospace text-uppercase">&mdash;</span>
      </li>
      <li id="row-severity" class="list-group-item d-flex align-items-center justify-content-between py-2 d-none">
        <strong>Alert Severity:</strong>
        <span id="ctx-severity" class="badge">&mdash;</span>
      </li>
      <li id="row-time" class="list-group-item d-flex align-items-center justify-content-between py-2 d-none">
        <strong>Triggered Time:</strong>
        <span id="ctx-time" class="text-muted small">&mdash;</span>
      </li>
      <li id="row-details" class="list-group-item py-2 d-none">
        <strong id="label-details" class="d-block mb-1">Firing Context:</strong>
        <code id="ctx-details" class="d-block p-2 bg-light border rounded small" style="white-space: pre-wrap; word-break: break-all;">&mdash;</code>
      </li>
    </ul>
  </div>
</div>

<script>
  (function() {
    const params = new URLSearchParams(window.location.search);
    const metadata = params.get('metadata');
    if (!metadata) return;

    try {
      
      const base64 = metadata.replace(/-/g, '+').replace(/_/g, '/');
      const jsonStr = decodeURIComponent(escape(window.atob(base64)));
      const data = JSON.parse(jsonStr);

      if (data) {
        let hasData = false;

        if (data.db) {
          document.getElementById('ctx-db').textContent = data.db;
          document.getElementById('row-db').classList.remove('d-none');
          hasData = true;
        }

        if (data.type) {
          document.getElementById('ctx-type').textContent = data.type;
          document.getElementById('row-type').classList.remove('d-none');
          hasData = true;
        }

        if (data.severity) {
          const severityBadge = document.getElementById('ctx-severity');
          const severity = data.severity.toLowerCase();
          severityBadge.textContent = severity.toUpperCase();
          if (severity === 'critical') {
            severityBadge.className = 'badge bg-danger';
          } else if (severity === 'warning') {
            severityBadge.className = 'badge bg-warning text-dark';
          } else {
            severityBadge.className = 'badge bg-info';
          }
          document.getElementById('row-severity').classList.remove('d-none');
          hasData = true;
        }

        if (data.t) {
          const date = new Date(data.t * 1000);
          document.getElementById('ctx-time').textContent = date.toLocaleString();
          document.getElementById('row-time').classList.remove('d-none');
          hasData = true;
        }

        if (data.details) {
          document.getElementById('ctx-details').textContent = data.details;

          
          const labelDetails = document.getElementById('label-details');
          if (data.type === 'object') {
            labelDetails.textContent = 'Object Metadata Details:';
          } else if (data.type === 'report') {
            labelDetails.textContent = 'Report Description:';
          } else {
            labelDetails.textContent = 'Firing Context:';
          }

          document.getElementById('row-details').classList.remove('d-none');
          hasData = true;
        }

        if (hasData) {
          document.getElementById('pslens-context-panel').classList.remove('d-none');
        }
      }
    } catch (e) {
      console.error('Failed to parse operational context metadata:', e);
    }
  })();
</script>


## Customized Objects Inventory Report

**Report ID:** `objects-customized-inventory`
**Category:** Hygiene

## Purpose

This report provides a complete inventory of all customized PeopleSoft objects across ten major object types. It answers the question: "What did we customize in this environment?"

Anything not stamped `PPLSOFT` is something you'll have to defend during an upgrade.

## Definition of "Customized"

An object is considered customized if its `LASTUPDOPRID` (last updated by operator) is **not** `PPLSOFT`. Objects delivered by Oracle PeopleSoft are stamped with `PPLSOFT` when installed. Any object modified by a customer operator will have a different value.

## Object Types Covered

|     Object Type      | PeopleSoft Table |     psLens Detail Page      |
| -------------------- | ---------------- | --------------------------- |
| Records              | PSRECDEFN        | `/records/{name}`           |
| Fields               | PSDBFIELD        | `/fields/{name}`            |
| Pages                | PSPNLDEFN        | `/pages/{name}`             |
| Components           | PSPNLGRPDEFN     | `/components/{name}`        |
| Menus                | PSMENUDEFN       | `/menus/{name}`             |
| Application Packages | PSPACKAGEDEFN    | `/apppackages/{name}`       |
| Application Engines  | PSAEAPPLDEFN     | `/appengines/{name}`        |
| SQL Objects          | PSSQLDEFN        | `/sqlobjects/{name}`        |
| Service Operations   | PSOPERATION      | `/serviceoperations/{name}` |
| Roles                | PSROLEDEFN       | `/roles/{name}`             |

## Data Flow

```text
1. For each object type:
   Query the primary table with LASTUPDOPRID <> 'PPLSOFT'
   (using paginated batches of 500 rows)
        |
        v
2. Collect all results across all pages
        |
        v
3. Generate summary table with counts per object type
        |
        v
4. Generate per-type detail sections with links to psLens detail pages
```

## Report Output

The report contains:

- **Header** with database name, generation timestamp, and definition of "customized"
- **Summary table** showing the count of customized objects per type and a grand total
- **Detail section per object type**, each with a markdown table listing:
  - Object name (linked to the psLens detail page)
  - Description (where available)
  - Object Owner ID (where available)
  - Last Updated By operator
  - Last Updated timestamp

## Parameters

This report has no configurable parameters.

## Interpreting Results

- **High counts** in a specific object type indicate heavy customization in that area. This increases upgrade risk for those object types.
- **Object Owner ID** (`OBJECTOWNERID`) shows the functional owner of the object (e.g., a product line or module). A customer-specific owner ID confirms the object is a true customization vs. a third-party product extension.
- **Last Updated By** shows which operator last touched the object. Objects last updated by a system batch operator may have been auto-modified vs. intentionally customized.
- Objects with no entry in a section means that type has no customizations, which is worth noting for upgrade planning.

## Use Cases

1. **Pre-upgrade assessment**. Run this report before a PeopleTools or application upgrade to understand the full scope of customizations that will need to be reviewed and re-applied.
2. **Customization audit**. Share with Oracle support or an implementation partner to get an accurate picture of what has been changed in the environment.
3. **Developer handoff**. Use as a starting inventory when onboarding new team members or transferring system ownership.
