Sales GL Detail BAQ

I am making a BAQ to get all detail posted to our Sales GL accounts. Right now i have the TranGLC linked to InvcDtl. I have 2 issues identified below I am trying to look for a work around to account for those.

Goal:
-See ALL journal transactions within the specified GL account range.
-Ones that are linked to invoices, I want to see more detail (Part,Part Description, Customer, Invoice#, Quantity)
-If it is just a General Journal (GJ) The above fields can be blank but i still want the debit/credit to show up on the BAQ and maybe pull in the Description.
-If it is a Cash Receipt Journal (CR). I want it to also bring in Customer and Invoice#

I have identified 2 issues.
-Cash Receipt Journals Key1 is NOT an invoice number but SJ/AJ journals Key1 = Invoice number so the link between TranGLC and InvcDtl is causing a Bad SQL Statement as a result when a CR journal is present.
-General Journals are not showing up in general (uncommon but would still like to have 1 report to pull it all).

Worst case scenario is I can run 2 different BAQs and stitch them together outside Epicor but ideally this would 1 as one full data source.

—BAQ BELOW—

select
[TranGLC].[TranDate] as [TranGLC_TranDate],
[TranGLC].[GLAccount] as [TranGLC_GLAccount],
[TranGLC].[JournalCode] as [TranGLC_JournalCode],
[TranGLC].[DebitAmount] as [TranGLC_DebitAmount],
[TranGLC].[CreditAmount] as [TranGLC_CreditAmount],
[Customer].[Name] as [Customer_Name],
[InvcDtl].[PartNum] as [InvcDtl_PartNum],
[Part].[ProdCode] as [Part_ProdCode],
[InvcDtl].[LineDesc] as [InvcDtl_LineDesc],
[InvcDtl].[InvoiceNum] as [InvcDtl_InvoiceNum],
[InvcDtl].[OurShipQty] as [InvcDtl_OurShipQty],
[InvcDtl].[UnitPrice] as [InvcDtl_UnitPrice],
[InvcDtl].[ExtPrice] as [InvcDtl_ExtPrice],
[Part].[ClassID] as [Part_ClassID]
from Erp.TranGLC as TranGLC
left outer join Erp.InvcDtl as InvcDtl on
TranGLC.Company = InvcDtl.Company
and TranGLC.Key1 = InvcDtl.InvoiceNum
and TranGLC.Key2 = InvcDtl.InvoiceLine
left outer join Erp.Customer as Customer on
InvcDtl.Company = Customer.Company
and InvcDtl.CustNum = Customer.CustNum
left outer join Erp.Part as Part on
InvcDtl.Company = Part.Company
and InvcDtl.PartNum = Part.PartNum
where (TranGLC.GLAccount >= ‘401000’ and TranGLC.GLAccount <= ‘499999’ and TranGLC.TranDate >= ‘01/01/2025’)

1 Like

Remember that you can do subqueries, CTE’s, Unions all in BAQ. So you can make several “queries” all in one BAQ…

1 Like

How would that work in this scenario? I have not done a subquery before. Would I just have a new criteria for Key1 on TranGLC for this?

1 Like

Are you in Kinetic or 10 or 9?

1 Like

Is your company Phillips like Philips - United States | Philips?

1 Like

No, Phillips Industries.. We are in Kinetic.

2 Likes

okay, search this in your help: " Using SubQueries"

1 Like

I haven’t watched this whole thing, but maybe it will help you?

1 Like

Thanks I am looking into it all now. May not figure it out that quickly since this is a whole new thing to me. Looks like it has potential but i will have to mess with it to get it to work.

I am excel person and know only basic SQL logic. So i think in basic if/then haha
I figured out Key3 is the InvoiceNum on the CR

This is my Excel brain trying to word it.
If AND(Key1=InvoiceNum, Key2=InvoiceLine) or If Key3=InvoiceNum then pull AR data otherwise blank AR data and just TranGLC numbers.

2 Likes

I got ya. Yeah not a quick thing to learn! @hkeric.wci is hopeful that we can use Prism to prompt it to create these types of BAQs for us.

1 Like

Typical scenario folks will have several InnerSubQueries for each TranGLC Type. I think there are a few Epicor Demo BAQs we can find.

You picked the most difficult task, because doing it right determines the speed. If you are Multi-Book or Multi-COA you will have duplicates. If you do Backflush you will have too much TranGLC Data… You will have to make a Sub-Select to find your MainBook for example etc… If you want the PartClass GL Account you have to go to EntityGLC etc… It all depends how much you want the BAQ to do.

You should be fine if its just a few GL Accounts, here are some notes on joins etc, may be relevant to you.

TranGLC Matrix


TranGLC Key Map to Related Tables.xlsx (15.0 KB)

Some Notes

These are some TranGLC to PartTran notes, but some still apply to you, especiall the conversion from integer to nvarchar stuff.

Optimizing Joins between TranGLC and PartTran in Epicor

When joining the TranGLC and PartTran tables in Epicor (especially in BAQs), performance can vary dramatically depending on:

  • The direction of the join
  • Which table is used as the driving table
  • Data volume in each table for your specific query
  • Proper handling of data type conversions (since TranGLC keys are NVARCHAR(50))
  • Filtering on RelatedToFile = 'PartTran'

TranGLC acts as a bridge table linking General Ledger details to source transactions like inventory movements in PartTran.

Primary Indexes

Table Primary Index Fields
TranGLC Company, RelatedToFile, Key1, Key2, Key3, Key4, Key5, Key6
PartTran Company, SysDate, SysTime, TranNum

Join Options

There are two main strategies — choose based on which table has fewer qualifying rows after your filters (e.g. date range, TranType, etc.).

Option 1: Start from PartTran (usually better when filtering on dates / fewer PartTran records)

Use when you apply cut-off dates or other selective filters on PartTran (typical for inventory / PartTran reconciliation reports).

TranGLC Field PartTran Field Join Condition (in BAQ expression)
Company Company TranGLC.Company = PartTran.Company
RelatedToFile TranGLC.RelatedToFile = ‘PartTran’
Key1 SysDate TranGLC.Key1 = CONVERT(NVARCHAR(50), PartTran.SysDate, 1)
Key2 SysTime TranGLC.Key2 = CONVERT(NVARCHAR(50), PartTran.SysTime)
Key3 TranNum TranGLC.Key3 = CONVERT(NVARCHAR(50), PartTran.TranNum)
  • Why this often performs better: PartTran usually has date-based filters → smaller result set early → TranGLC is looked up efficiently.

Option 2: Start from TranGLC (better when filtering on GL periods / fewer TranGLC records)

Use when your main filter is on fiscal year/period, BookID, JournalCode, etc. (typical for GL reconciliation reports).

TranGLC Field PartTran Field Join Condition (in BAQ expression)
Company Company TranGLC.Company = PartTran.Company
RelatedToFile TranGLC.RelatedToFile = ‘PartTran’
Key1 SysDate CONVERT(DATE, TranGLC.Key1, 1) = PartTran.SysDate
Key2 SysTime TRY_CONVERT(INT, TranGLC.Key2) = PartTran.SysTime
Key3 TranNum TRY_CONVERT(INT, TranGLC.Key3) = PartTran.TranNum
  • Note: TRY_CONVERT is safer in newer versions (avoids errors on bad data); older versions may need plain CONVERT.

LEFT JOIN Considerations (from TranGLC to PartTran)

When you want all TranGLC records (even without matching PartTran), use a LEFT OUTER JOIN and safer conversions:

TranGLC.Company = PartTran.Company
AND TranGLC.RelatedToFile = 'PartTran'
AND TRY_CONVERT(DATE, TranGLC.Key1, 1) = PartTran.SysDate
AND TRY_CONVERT(INT, TranGLC.Key2) = PartTran.SysTime
AND TRY_CONVERT(INT, TranGLC.Key3) = PartTran.TranNum

BAQ Designer Tips

  • Never use the dropdown for non-Company fields — type the full expression manually (e.g. CONVERT(NVARCHAR(50), PartTran.SysDate, 1)).
  • Include TranGLC.RelatedToFile = 'PartTran' as a criteria or join condition.
  • Test both join directions with your real filters and compare execution plans / run times.
  • Add indexes or statistics if possible (DBA task).
  • Use SubQueries if the BAQ becomes complex — isolate the TranGLC ↔ PartTran part first.

Choosing the Correct Option

  • PartTran reconciliation report with date cutoffs → Option 1 (PartTran as starting point) usually faster.
  • GL Reconciliation by Fiscal Period / Year / Journal → Option 2 (TranGLC as starting point) usually better.

Wrong direction can cause 10×–100× slower performance due to table scans on large tables.

Frequently Asked Questions

Q1: Which table links GLJrnDtl to transaction tables (APInvHed, InvcDtl, PartTran, etc.)?
A: TranGLC is the central linking table.

Q2: How to link TranGLC to GLJrnDtl?

TranGLC Field GLJrnDtl Field Join Condition
Company Company =
BookID BookID =
FiscalYear FiscalYear =
FiscalYearSuffix FiscalYearSuffix =
JournalCode JournalCode =
JournalNum JournalNum =
JournalLine JournalLine =

Q3: General pattern to link TranGLC to any transaction table?
Filter TranGLC.RelatedToFile = 'TableName' and match Key1–Key6 to the table’s primary key fields (excluding Company).
If >6 key fields → Key1 often = SysRowID (e.g. TaxDtl).

Q4: BAQ errors linking non-character fields to TranGLC Keys?
Convert transaction fields → NVARCHAR(50):

Data Type Conversion Formula
INTEGER CONVERT(NVARCHAR(50), Table.Field)
DECIMAL CONVERT(NVARCHAR(50), Table.Field)
DATE CONVERT(NVARCHAR(50), Table.DateField, 1)
BIT/BOOLEAN CASE WHEN Field = 0 THEN 'False' ELSE 'True' END

Q5: BAQ still slow even with correct joins?

  • Verify join direction matches data volume.
  • Convert TranGLC Keys → transaction types instead (sometimes faster).
  • Use subqueries.
  • Reduce returned columns.
  • Apply tight filters early.

Q6: How to find a table’s Primary Key?
→ Epicor Data Dictionary Viewer → select table → look for index starting with PK_ (top of list).

Q7: How to find GL account for unposted transactions (e.g. AP Invoice expense line defaults)?
Join as usual + TranGLC.RecordType = 'A' (‘A’ = Account Data Only = unposted).

Record Types in TranGLC

  • A — Unposted (pre-posting engine)
  • R — Posted / Reference Data (after posting)

Q8: Multiple TranGLC rows per PartTran record?

  • Normal (one-to-many) — posting engine can create multiple GL accounts per transaction.
  • Filter RecordType to isolate posted/unposted.
  • Aggregate or use DISTINCT / grouping if needed.

Q9: Multiple TranGLC rows per GLJrnDtl record?

  • Normal when summarization is enabled — multiple transactions can summarize into one journal entry.
  • Filter RecordType and be aware of summarization settings in GL Transaction Types.

By selecting the appropriate join direction, handling conversions correctly, and filtering strategically, you can achieve significantly better BAQ performance when working with TranGLC and PartTran. Always test both options with your actual data and filters!

GL Journal Entry Missing on TranGLC Table & Related Questions

Q10: Why can’t I find a General Journal (Journal Code = GJ) in my BAQ when querying the TranGLC table? Does this mean the journal didn’t post?

Answer:
This behavior is working as designed.

  • General Journals (GJ) do not create records in the TranGLC table.
  • The TranGLC table exists specifically to link subledger transactions (AR, AP, AM, CM, PartTran, etc.) to the General Ledger.
    • Examples: Cash Receipts (from AR), AP Invoices, Inventory Adjustments, etc. appear in TranGLC.
  • Pure General Journal Entries (created directly in the GL module) are not considered subledger transactions, so they do not generate TranGLC records.

Where to find General Journals:

  • Query the GLJrnDtl table (General Ledger Journal Detail).
  • If the journal appears in GLJrnDtl, it has posted successfully and correctly affected the GL balances.

Additional table to check:

  • GLJrnDtlMnl (Manual General Ledger Journal Detail)
    • Contains records created via:
      • “Transfer from other modules” process
      • Direct G/L Journal Entry program
    • Before posting, these have a related GLJrnHed record.
    • After posting, they appear in GLJrnDtl.

Special case – Deferred Expenses:
Only General Journals that include Deferred Expense logic may create TranGLC records.
In that case, filter on:
TranGLC.RelatedToFile = 'GLJrnDtlMnl'

Q11: How does the “Summarize GL Account” setting work?

  • The system does summarize accounts into GLJrnDtl (the posted journal detail table) when summarization is enabled.
  • However, it does NOT summarize records in the TranGLC table.

Reason:
The Chart Tracker (and similar drill-down tools) relies on TranGLC to show every individual source transaction detail.
Summarizing TranGLC would break the ability to trace back to the original subledger documents (e.g., which specific AP invoice or PartTran created the GL entry).

Q12: When is the GLPeriodBal table populated?

GLPeriodBal is populated/updated whenever any posting process completes successfully.

It summarizes net movements for each:

  • Company
  • COA Code
  • Book ID
  • Fiscal Year
  • Fiscal Year Suffix
  • Fiscal Period
  • Account

Additional ways it gets updated:

  • Running “Verify Balances”“Transfer Opening Balances to New Year” process
  • Fiscal Period 0 typically stores the beginning/opening balance for the year.

Q13: What are common signs of corrupt or problematic GLJrnDtl records?

Look for these issues:

  1. Balance Flags missing/inconsistent
    The following flags should all be 1 (true) for the record to appear correctly in the Trial Balance report:

    • PerBalFlag
    • TBFlag
    • DailyBalFlag
  2. Missing GL Accounts in balance fields

    • BalanceAcct and TrialAcct must contain valid GL account numbers.
    • If either is blank (''), the record will be excluded from Trial Balance.

Quick query to find problem records:

SELECT *
FROM Erp.GLJrnDtl
WHERE PerBalFlag = 0
   OR TBFlag     = 0
   OR DailyBalFlag = 0
   OR BalanceAcct = ''
   OR TrialAcct   = ''

TranGLC Duplicate Records – Understanding RecordType & UserCanModify

You may see multiple rows in TranGLC for what appears to be the same transaction. Common causes:

  • Different RecordType values:

    • A = Account Data Only (unposted / pre-posting)
    • I = Instance GL Control
    • R = Reference GL Control (most common for posted subledger links)
  • UserCanModify = 1 often appears on reusable/instance controls that allow user overrides.

Example query to inspect duplicates:

SELECT RecordType, UserCanModify, *
FROM Erp.TranGLC
WHERE Company = 'YourCompany'
  AND Key2 = '1250505'           -- example key (adjust as needed)
  AND UserCanModify = 1

GL Control Types – Quick Reference

Type Purpose Visible/Modifiable? Populates TranGLC? Typical Use Case
Reusable Flexible, user-modifiable GL controls (e.g., Customer, Part defaults) Yes Yes (via business entities) AR/AP/Inventory defaults
Instance Specific account for one item/transaction Sometimes Yes (pre-posting) PORel, specific rules
Reference System-generated link between source transaction and GL No (hidden) Yes PartTran → GL, APInvDtl → GL, etc.

Note on APInvExp (AP Invoice Expense Lines):
Duplicates with different RecordTypes can be hard-coded behavior in some versions for expense distribution.

Another common cause of duplicates:

  • Multiple COAs (Chart of Accounts) or multiple Books active in the system.
  • Transactions may post to each book, creating separate TranGLC rows.

MainBook – How It’s Calculated & Used

GLBook.MainBook is a flag (usually 1 = main/primary book, 0 = secondary/alternate book).

Typical usage in BAQs (example join):

LEFT OUTER JOIN Erp.GLBook GLBook
  ON  TranGLC.Company  = GLBook.Company
  AND TranGLC.BookID   = GLBook.BookID
  AND TranGLC.COACode  = GLBook.COACode
  AND GLBook.MainBook  = '1'           -- only main book

Common filter to include only main book transactions:

WHERE (TranGLC.BookID IS NULL OR GLBook.MainBook = '1')

This ensures the query focuses on the primary ledger and avoids inflating results with secondary books (if your company uses multi-book accounting).

By understanding these behaviors, you can build more accurate BAQs and avoid chasing “missing” or “duplicate” records that are actually functioning as designed in Epicor’s GL architecture.

5 Likes

This is honestly one BAQ I’d love to see Prism tackle and solve elegantly. After building and testing ~15 different BAQs covering various scenarios, I finally found a clean approach that completely avoids touching TranGLC and PartTran altogether, especially when I just want GLJrnDtl metadata. It handles everything in a single query and runs in under 10 seconds—even on sizable datasets.

The moment you introduce backflushing (or any high-volume PartTran activity), TranGLC explodes with records. Even with aggressive SUM() + GROUP BY, it still becomes a major bottleneck. Worse, you can’t cleanly aggregate everything in TranGLC because a single transaction can post to multiple GLJrnDtl lines (different accounts, costs, etc.). If you try flipping the logic and exploding from GLJrnDtl downward, you end up duplicating TranGLC rows massively → query times jump to several minutes, plus you start dealing with gaps, mismatched summarization, and orphaned lines.

Avoiding the TranGLC ↔ PartTran join path entirely was the real breakthrough.

Most people go to TranGLC because it helps them link to PartNum, PONum, PackNum, PackSlip, OrderNum, GLJrnDtl, InvcDtl, etc… People want to know what Vendor, Customer etc this transaction is tied to, and GLJrnDtl is just one level above TranGLC and usually is enough. With BAQ Params you can always link a Split Pane and get additional details for a GLJrnDtl

2 Likes

Music Video Wtf GIF

1 Like

If I reveal the answer then Prism will train on it :smiley: I want to see it beat me and make me feel like my job is on the line. If you want the answer DM.

2 Likes