Skip to content
View Categories

The journal_id Taxonomy

4 min read

Audience: admin, developer · Last updated: 2026-05-19 · Edit on GitHub

The journal_id Taxonomy #

Bizuno records every transactional event — quotes, orders, invoices,
payments, credits, inventory builds, work orders, quality tickets — as a
single row in journal_main, discriminated by an integer journal_id
field. Understanding this taxonomy unlocks the rest of the codebase: you
can read any report SQL, follow any customization, and pick the right
transaction type from a UI you’ve never seen before.

This page is the canonical reference. The richer per-journal narrative
(GL postings, fields, lifecycle) lives in
Journals.


Mental model #

┌──────────────────────────────────────────────────────────────┐
│  journal_main                                                │
│  ──────────────────────────────────────────────────────────  │
│  id, journal_id, post_date, period, contact_id_b, store_id,  │
│  invoice_num, total_amount, closed, recur_id, ...            │
└──────────────────────────────────────────────────────────────┘
                          │
                          │  ref_id
                          ▼
┌──────────────────────────────────────────────────────────────┐
│  journal_item                                                │
│  ──────────────────────────────────────────────────────────  │
│  one row per line item (or GL leg); sku, qty, debit, credit, │
│  gl_account, gl_type, reconciled, ...                        │
└──────────────────────────────────────────────────────────────┘

A typical sales invoice (jID=12) is one journal_main row plus several
journal_item rows: one per inventory line, one or more per GL posting
(debit AR, credit revenue, debit COGS, credit inventory). Every transaction
in Bizuno follows this shape, regardless of whether it’s a sale, a quality
ticket, or a work order.

The journal_id itself drives:

  • Which controller renders the entry screen (controllers/phreebooks/main.php
    for most PB journals; controllers/quality/tickets.php for jID=30; etc.)
  • Which journal class posts it (controllers/phreebooks/journals/jNN.php)
  • Which GL postings happen (per the journal class’s Post() method)
  • Which dashboard widgets count the entry
  • Which audit-log message describes it (lang("journal_id_$jID"))
  • Which forms/reports apply (PhreeForm filters by journal_id)

Change a row’s journal_id and you’ve effectively reclassified the
transaction across the whole system. Don’t do this casually.


Reference table — PhreeBooks core (0–29) #

jID Name What it is Class file
0 Search Journal Base class for searches (not a real transaction) j00.php
2 General Journal Manual GL adjustment / journal entry j02.php
3 Request For Quote Outbound RFQ to a vendor (no GL) j03.php
4 Purchase Order Outbound PO to vendor (no GL until receive) j04.php
6 Purchase Vendor invoice / bill (Dr inventory or expense, Cr AP) j06.php
7 Vendor Credit Credit memo received from vendor (reverses 6) j07.php
9 Sales Quote Outbound quote to customer (no GL) j09.php
10 Sales Order Inbound order from customer (no GL until invoice; supports recurring) j10.php
12 Sales Customer invoice (Dr AR, Cr revenue + tax; Dr COGS, Cr inventory) j12.php
13 Credit Memo Customer return / credit (reverses 12) j13.php
14 Assembly Inventory build (pulls components, produces assembly) j14.php
15 Store Transfers Move inventory between stores j15.php
16 Adjustment Inventory adjustment (count, write-down/up) j16.php
17 Vendor Refund Cash refund from vendor (Dr cash, Cr AP) j17.php
18 Cash Receipt Customer payment against AR (Dr cash/undeposited, Cr AR) j18.php
19 Point Of Sale Immediate-cash sale (Dr cash, Cr revenue + inventory) j19.php
20 Pay Bills Vendor payment (Dr AP, Cr cash); supports ACH + bulk pay-by-date j20.php
21 Point Of Purchase Immediate-cash purchase (Dr inventory/expense, Cr cash) j21.php
22 Customer Refund Cash refund to customer (Dr AR, Cr cash) j22.php

The lang key for the human-readable label is journal_id_<N> (e.g.
lang('journal_id_12') → “Sales”). Many screens use lang("journal_id_$jID_mgr")
for the manager label (“Sales Manager”).


Reference table — extension journals (30+) #

Extension modules use journal IDs ≥ 30 to avoid colliding with the
PhreeBooks core. These transactions still live in journal_main and follow
the same shape, but most don’t post to the GL — they use the structure for
its workflow / lifecycle / audit-trail value.

jID Name Module What it is Source
30 Quality Ticket quality Corrective/Preventive Action ticket controllers/quality/tickets.php
31 Quality Audit quality Audit instance controllers/quality/audits.php
32 Work Order inventory Production build job (used by jID=14 assembly when complete) controllers/inventory/build.php
34 Training quality Training instance controllers/quality/training.php
35 Maintenance administrate Scheduled-maintenance instance controllers/administrate/maint.php

If you’re writing a custom extension, use 40+ for your own journal IDs
to leave room for future core additions in the 30s. See
Custom journal type.


Anatomy of a journal class #

Every journal under controllers/phreebooks/journals/jNN.php extends the
shared base in common.php and implements a small set of conventions:

namespace bizuno;

class jNN extends jCommon
{
    public $journalID = NN;

    public function Post()        { /* build the journal_item rows */ }
    public function unPost()      { /* reverse them */ }
    public function postJournalEntry() { /* the GL legs */ }
    // ...
}

The Post() method is where the journal’s accounting personality lives. A
read of j12.php::Post() is the single best way to understand exactly what
posting a customer invoice does to the GL. Likewise j20.php::Post() for
the vendor-payment side.

Extension journals (jID ≥ 30) typically don’t live under
controllers/phreebooks/journals/. They’re saved through their own
controller (e.g. controllers/quality/tickets.php::ticketSave()) which
writes to journal_main directly and skips the GL-posting machinery.


How journal_id drives behavior across modules #

System component How it uses journal_id
Manager grids Every PhreeBooks grid filter is WHERE journal_id = N for the relevant N
Dashboards Each widget is hard-coded to a journal_id (e.g. qa_stop_work filters on jID=30)
Audit log Action description includes lang("journal_id_$jID")
PhreeForm Reports + forms filter their data source by journal_id
Recurring transactions recur_id links a chain of journal_main rows that share a journal_id
Permissions Security keys often follow j<N>_mgr (e.g. j12_mgr for Sales Manager access)
Next-reference counter next_ref_j<N> meta key per journal type (next invoice number, next PO number)

Why this matters #

The journal ID is Bizuno’s primary discriminator. Almost any question of
the form “Where does X live?” resolves to “Find its journal_id, then read
the journal class and the manager controller.”
Yet most existing
introductions to Bizuno don’t name it at all, and end-users hit it for the
first time as a column in a custom report they can’t make sense of.

If you walk away from this page with one thing, let it be the mental model:
one row in journal_main per transaction, the journal_id field tells
you what kind, and the per-jID file is where the behavior lives.


Related #

Powered by BetterDocs

Leave a Comment