Skip to content

Audit

Audit lists every sent routing of the project, whoever sent it, grouped by project, state and date. It is shown to the admin, Document Controller and Procurement Controll groups.

Audit: every routing of the project, grouped by project, state and date
Audit: every routing of the project, grouped by project, state and date · click to enlarge

Toolbar: View, Edit, Delete, Refresh, Search, Print, Download, Group Routing, Return, Clear Return Status.

Return

Overview

Return closes the loop on a reviewed document: an auditor produces an outgoing Transmittal Out (TSO) package and marks the routing returned. The business semantics are the ones INACT has always had (same auditor roles, same status write, same correspondence record, same validation). v3 rebuilt the generation engine as an OOP Transmittal class that renders via HTML2PDF, added a config gate, and modernised the download flow.

Prerequisites and where it sits

Upload → routing created → reviewers act → routing CLOSED

Return (this) → builds TSO + sets ts_routing.rout_return_status='Y', rout_return_date=today

A routing can be returned when its rout_status is closed, it is not already returned (rout_return_status != 'Y'), and the selection shares one project and one originator. And enable_return_on_audit must be '1' for the button to appear at all.

User flow

  1. Open Document Routing, Audit tab. Auditor groups only; the tab is hidden otherwise.
  2. Select one or more closed routing rows, same project and originator.
  3. Click Return (downloadrout). Present only when enable_return_on_audit=1.
  4. The system validates, reserves a transmittal number, builds the TSO, marks the routing returned, and streams the packages to the browser.

How it works

Gating and button

The Audit tab is shown only to admin, Document Controller and Procurement Controll (routing_header.inc.php). The same three names appear in all five forks. The Return button is created only when the flag is on, in routing_browse.htm:

js
if("{enable_return_on_audit}" === "1") {
    procBarAudit.addButton('downloadrout', 9,"Return","download.svg");
}

JOTRE and Timas have no Return button at all

In those two forks the downloadrout line is commented out on the Audit toolbar, on the Outbox toolbar and in the overflow menu, and the enable_return_on_audit key does not exist. The AJAX handler is still in the code, so the feature is reachable only by a direct request.

Front-end

Downloadrout() in js/routing.js confirms, then calls ajax=transmittaloutgoingdownload&ids=<mapids> and downloads each returned archive client-side via blob and XMLHttpRequest. This supports batch returns, several archives in one action.

Back-end

routing_handler_ajax.php routes transmittaloutgoingdownload to generateTransmittalOutSantos($ids) in routing.inc.php, which uses the Transmittal class:

php
$t = new Transmittal("return", $html2pdf);
$t->setRoutId($routids);
$t->setBatchRouting(true, $routids);
$t->saveReturnAuditTransmittalNumber();   // reserve number in ts_transmittal_data
$t->generateTransmittal();                // build PDF via HTML2PDF
$t->storeFile();                          // write to disk

Then the core writes:

  • Mark returned: UPDATE ts_routing SET rout_return_date=<now>, rout_return_status='Y' WHERE rout_id IN (...), via $pdo->prepare()->execute().
  • Outgoing correspondence: handleProcessTransmittalCorrespondence() inserts ts_correspondence with corrkind_id='2' and links the file.

Numbering

saveReturnAuditTransmittalNumber() reserves the next number in ts_transmittal_data, keyed by year, company, trans_type='out', project and owner. A more granular scheme than v2's simple increment.

Generation engine: HTML2PDF, with the legacy Excel path still present

The active Return path renders the transmittal as HTML to PDF via HTML2PDF inside the Transmittal class (routing_handler_transmittal.class.php, writeHTML() / Output()). generateTransmittalOutSantos() calls new Transmittal in all five forks.

Hybrid, not a clean replacement

The legacy per-company Excel mechanism is still in the code: writeExcelSantosTransmittalOut() and the ts_company_transmittal / comp_file_name lookups (docUpload/routing/) remain in routing.inc.php in every fork. Confirm which path your build wires up before assuming Excel templates are unused. Both exist.

Database tables affected

TableOperationNotes
ts_routingupdaterout_return_status='Y', rout_return_date=today
ts_correspondenceinsertoutgoing header (corrkind_id='2')
ts_file_explorer, ts_map_corr_fileinsertstored transmittal file plus link
ts_transmittal_datainsert / updatenumbering (year / company / project / owner, out)
ts_company_transmittalselectper-company template, legacy path, if used

Validation and error handling

The checks and messages in routing.inc.php: "You cannot return open document(s)", "Document(s) already returned", "You cannot return document(s) with different contractor/originator", and a different-project guard.

The "Ready to Return" tab

Master, Jadestone and Medco have an Audit-adjacent tab backed by routing_handler_ready_to_return.php, listing rout_status='close' AND rout_return_status='N'. JOTRE and Timas do not have the file.

Instance differences (Return)

Checked on 2026-09-06.

InstanceDifference
JOTRENo Return button: downloadrout is commented out everywhere in routing_browse.htm. No enable_return_on_audit key. No Ready to Return tab.
TimasSame as JOTRE.

Master, Jadestone and Medco match on the gate, the button, the auditor roles, the Transmittal class and the Ready to Return tab.

Clear Return Status

Dormant. The toolbar button is commented out.

The feature is not reachable from the UI in any of the big five. The still-broken handler remains in the code. In master, Jadestone, Medco and Timas it would fatal if act=clearreturn were posted directly, because it calls the decommissioned iw_mysql_query(). In JOTRE that helper still works, so there the handler would actually run, with the bug below. Checked 2026-09-06.

Overview

In v2, Clear Return Status was an active Audit-tab button with a well-known naming bug: despite "Clear", it set rout_return_status='Y' (mark returned) rather than clearing it. The v2 doc flagged this for a v3 fix.

What actually happened in v3: the fix did not land. Instead, the button was commented out. The feature is gone from the UI, but the broken handler is unchanged.

What the field means

rout_return_status on ts_routing: 'Y' = returned to originator, 'N' = not returned. 'N' is written only by internal approve and sign-off paths, never by a user-facing button.

Current state of the button

In routing_browse.htm:

js
// procBarAudit.addButton('aud_clear', 10,"Clear Return Status","bar_channel_trace_all.svg");

The line is commented out, and so is the overflow-menu entry further down. The button is never created, so there is no UI path to invoke act=clearreturn. This is the same in all five forks.

The handler, unchanged and still broken

In routing_handler_post.php:

php
} elseif ($_POST["act"] == "clearreturn") {
    if ($_LOGIN_GROUP_ID != "admin" && !havePrivilegesResource($_LOGIN_GROUP_RESOURCE, $mod_code, 'edit')) {
        echo "denied"; exit;
    }
    $sumId = explode(",", $_POST['id']);
    for ($k = 0; $k < count($sumId); $k++) {
        if (iw_mysql_query("update ts_routing set rout_return_status='Y' where rout_id='$sumId[$k]'", "...")) {
            echo "Row Updated.";
        } else {
            echo "Error clear return status.";
        }
    }
    // br_logs($_LOGIN_ID,'clear',$qry);
    exit;
}

Every v2 defect is still here:

  • Still sets 'Y', not 'N', the same inverted behaviour the name promised to fix.
  • Still does not set rout_return_date. A "cleared" row shows Returned = Yes with an empty return date.
  • Audit log still commented out (// br_logs(...)).
  • Still iw_mysql_query with unescaped $sumId[$k]: SQL-injection-prone, and on the legacy API rather than $pdo. In four of the five forks that legacy API throws, which is the only reason the handler cannot do damage there.

The only v3 change to the handler itself is the privilege check: v2 used havePrivileges($_LOGIN_GROUP_ID, ...); v3 uses resource-based havePrivilegesResource($_LOGIN_GROUP_RESOURCE, ...) with an admin bypass. The new authorisation model, applied here but not fixing the core bug.

Database tables affected

TableOperationNotes
ts_routingupdaterout_return_status='Y' per rout_id. Does not set rout_return_date.

What a real fix would need

Write 'N' and clear the date, or rename the action to "Mark as Returned" and set the date. Restore logging. Escape the input or move to $pdo. Until then, leave the button commented out.

Instance differences (Clear Return Status)

Checked on 2026-09-06.

InstanceDifference
JOTREiw_mysql_query() is still live, so a direct act=clearreturn POST runs and sets 'Y' without a date. Everywhere else the same POST fatals on entry.

Button state and handler text are identical in all five forks.