Journal Transactions (GL301000) is the screen every other module's release process feeds without you ever seeing it directly — an AP Bill release, an AR Invoice release, an Inventory Adjustment posting, all end up as a Batch header with GLTran lines, and this screen is where you'd look at (or, less often, hand-key) that same structure directly. The graph is JournalEntry; almost every customization on it revolves around the fact that a batch has to balance before it can post.
Batch and GLTran
A Batch record is the header — module, ledger, period, status — and each GLTran row is a debit or credit against an account/subaccount combination, optionally tagged with branch, project, and task. The screen enforces that the batch's control total matches the sum of its lines before it will let you release; that check happens in the graph, not the database, so a customization that inserts GLTran rows directly via SQL rather than through the graph can produce an unbalanced batch that the UI will refuse to touch.
Key tabs
- Details — the GLTran grid itself: account, subaccount, branch, debit/credit amount, and optional project/task.
- Financial — ledger, currency, and the reversal/auto-reverse settings for accrual-style entries.
- Currency — only meaningful when the batch's currency differs from the base currency; this is where rate overrides live.
Extending JournalEntry
A common ask is restricting which account/subaccount combinations a given role can post to beyond what account-level restriction groups already do — for instance, blocking postings to a "closing entries only" account outside of a designated close window. That's a GLTran_RowPersisting or Account_CacheAttached validation attribute on the graph extension, checked against the current period status rather than hardcoding dates.
public class JournalEntry_Extension : PXGraphExtension<JournalEntry>
{
protected virtual void GLTran_AccountID_FieldVerifying(PXCache cache, PXFieldVerifyingEventArgs e)
{
int? accountID = (int?)e.NewValue;
Account acct = PXSelect<Account,
Where<Account.accountID, Equal<Required<Account.accountID>>>>
.Select(Base, accountID);
if (acct?.GetExtension<AccountExt>()?.UsrClosingOnly == true && !IsWithinCloseWindow())
throw new PXSetPropertyException("This account only accepts postings during period close.");
}
}
Custom fields and tabs via the Customization Project Editor
Adding a field to the GLTran grid (a custom classification code, say) is routine, but remember that GLTran rows are also generated by every other module's release process — a required custom field on GLTran will need a sensible default supplied by every module that posts to GL, or those releases start failing with validation errors that have nothing to do with the screen where they surfaced.
Common validation and event-handler use cases
Beyond posting restrictions: auto-populating a subaccount segment from a custom field on the source document type, enforcing that manual journal entries above a threshold require a note/attachment before release, and blocking postings to closed periods for specific ledgers where the stock period-status check isn't granular enough. All are handled through the existing RowPersisting/FieldVerifying extension points on JournalEntry, not by working around the release pipeline.
Gotchas
A batch created by another module's release (an AP Bill, for instance) is generally not meant to be hand-edited from this screen — the source document owns it, and manual edits here can desynchronize the two. Auto-reversing entries create a second batch dated the first day of the next period automatically; a customization that watches for "new batch created" events will see these and needs to filter on Batch.Module/origin rather than assuming every batch was manually entered. And multi-currency batches store both the transaction-currency and base-currency amounts on GLTran — code that only reads one of the two will misreport for anything not in the base currency.
Direct SQL inserts into GLTran bypass the balance check, the period-status validation, and the currency conversion logic the graph performs on save. If a batch needs to be created programmatically, do it by instantiating JournalEntry and going through its data views, not by writing to the table directly.
Wrapping up
This screen is the common landing zone for every module's financial impact, which makes it tempting to customize broadly and risky to customize carelessly. Respect the balance check, the period-status rules, and the fact that most batches here weren't created by a human — and the customization will hold up across the modules that quietly depend on it.
Independent software engineer in Nairobi specialising in Acumatica customisations, Laravel backends, and tax fiscalisation integrations across East and Southern Africa.