Ownware
Home›Packora›Manual
Packora · Manual

Packora Manual, as shipped in the download

Packora — User Manual

A packaging producer register: SKUs, materials, weights and the tonnage a report asks for. Version 3.1.4 [src: app/controllers/api.php:161].

About this manual

Every statement here was written by reading Packora's own source, and each one carries the file it came from in a bracketed src marker. Paths are relative to the folder this docs directory sits in. If a sentence disagrees with the application, the application is right and this manual has a bug — the markers exist so you can check rather than take our word for it.

Nothing is described that the code does not do. Where something is deliberately limited, that is said plainly rather than left out.

Read this before anything else

Packora ships no built-in fee schedules, no thresholds and no statutory deadlines. Rates and deadline dates are entered by you, and every estimate is labelled as an estimate [src: app/src/Register.php:13].

That is the product's own stated position, not a caveat added by this manual, and it is the right one. Nothing in Packora tells you what any scheme charges, what any threshold is, or when anything is due. It multiplies weights you supply by units you supply, and applies a rate you supply.

Nothing here is legal or compliance advice. Confirm your obligations with your producer responsibility organisation or your adviser.

What it computes

Three lines of arithmetic, stated in the source [src: app/src/Register.php:5]:

line weight    = component weight (mg) × units sold
material total = Σ line weights per material, per state × year
fee estimate   = material mg × your rate (¢/kg), rounded half up in integer space

Everything stays in integer milligrams and integer cents until the final display conversion [src: app/src/Register.php:9]. Sums are done in PHP rather than in SQL, deliberately, so both database engines produce identical integer results [src: app/src/Register.php:10].

Negative inputs floor at zero rather than subtracting [src: app/src/Register.php:27].

No rate means no estimate — never a zero

If you have not entered a rate, the fee comes back as nothing at all, and the source says why in the same breath: "no estimate", never a fake $0 claim [src: app/src/Register.php:34].

A product that showed £0.00 for an unpriced material would be inviting somebody to file on a number that was never calculated.

The arithmetic itself is integer throughout, with a documented fallback used only at magnitudes beyond 64-bit safety — far past any real input [src: app/src/Register.php:35].

Deadlines

A deadline badge is one of four states, and the first matters most: none, meaning no date has been entered — "verify with your PRO" [src: app/src/Register.php:50]. Then overdue, due soon, or fine.

Due-soon defaults to 60 days [src: app/src/Register.php:22].

The reminder ladder

You set rungs — say 60,30,7 — and each fires once per deadline date. The source gives the reason in a sentence worth keeping: one warning two months out is a rumour, not a reminder [src: app/src/Register.php:69].

Your input is parsed strictly, and the strictness is deliberate. The parser splits on separators and then demands a clean positive integer, rather than splitting on "not a digit" — because the lazy version would turn a typed -5 into a five-day rung, giving you a reminder you never asked for, which the source calls worse than being told your input was ignored [src: app/src/Register.php:75].

Rungs beyond a year are dropped, because a year out is not a reminder [src: app/src/Register.php:82].

An overdue deadline always maps to rung zero, so a missed filing keeps being reported rather than falling off the bottom of the ladder [src: app/src/Register.php:92].

Reminders latch, so nothing fires twice

A reminder is sent only when the ladder tightens — never twice for the same rung, and never again on a re-run [src: app/src/Register.php:108].

A new or changed deadline date starts the ladder fresh [src: app/src/Register.php:114].

So you can run the reminder job hourly, or twice, or after restoring a backup, and nobody is emailed the same warning again.

When the ladder is checked

It is checked each time someone opens the dashboard, and by a token-guarded cron route, reminders/run?t=<token>, using the scheduled-backup token [src: app/controllers/v3.php:592]. Both paths call the same watcher with the same latch [src: app/controllers/api.php:58], so a daily cron job sends each step in the months nobody opens Packora, and never twice.

Completeness — the gaps are reported, not hidden

Two reports exist for exactly the failure that makes a register wrong without looking wrong.

SKUs with no packaging components are listed [src: app/src/Register.php:221]. Their sales weigh nothing in the register — the tonnage is understated and nothing on the report would tell you.

Sales rows whose SKU code matches no SKU are flagged, and the source is explicit that they are never silently dropped [src: app/src/Register.php:229].

Those two lists are the difference between a total you can file and a total that merely adds up.

Exporting

CSV to RFC 4180 with formula-injection neutralisation: a cell beginning =, +, -, @, tab or carriage return gets a leading apostrophe unless the value is numeric, so -5 and -12.5 export as real negative numbers while =SUM(A1) and +HYPERLINK(...) are defused [src: app/src/Register.php:246].

Recorded filings

The register holds today's packaging, so a component weight changed next year changes what this year recomputes to. When you file, an administrator can record the pack for that state and year: the material totals and the SKU-level rows exactly as they stand, their total and a SHA-256 of them, with who recorded it, when and a note such as the PRO's confirmation number [src: app/controllers/app.php:960]. The report page lists recorded filings and says whether the register still computes the same total today [src: app/controllers/app.php:974]; each can be downloaded again as CSV exactly as recorded [src: app/controllers/app.php:1006]. Recording files nothing with anyone.

Users and roles

Three roles [src: app/src/Auth.php:50]. Packora had none before this version, and the migration defaults every pre-existing account to admin so an upgrade cannot take rights away from anyone who already had them [src: app/src/Auth.php:41].

The line the source draws is a good one [src: app/src/Auth.php:46]:

A member keeps the register — SKUs, components, units sold, imports. They cannot change fee rates, jurisdictions, users or settings, because those decide what the filing SAYS rather than what it contains.

Permissionviewermemberadmin
.view permissions, report.viewyesyesyes
audit.viewyesyesyes
sku.*, component.*, sales.*, import.*—yesyes
view.save—yesyes
rates, jurisdictions, settings, users——yes

The audit trail is granted to a viewer explicitly — audit.view is named in the viewer's list rather than arriving through the wildcard [src: app/src/Auth.php:53]. That is a deliberate decision here, not an accident: the viewer role is described as reading "the register, reports and the audit trail" [src: app/src/Auth.php:44].

Backups follow the model

Packora's database backup downloads are permission-gated, requiring the settings permission [src: app/controllers/api.php:496]. A viewer cannot download the database.

The API and agent access

Six tools are exposed to an agent, of which one writes [src: app/controllers/v3.php:65]: listing SKUs, SKU detail, a tonnage report, a states summary and a data-gaps report on the read side; upserting a SKU on the write side.

The instructions make one guarantee worth having: nothing here re-derives a tonnage — the reports come from the same functions the register screen renders [src: app/controllers/v3.php:63].

So an agent's figures and your screen's figures cannot disagree. There is no second implementation to drift.

What Packora does not do

It does not know your fees, thresholds or deadlines [src: app/src/Register.php:13]. You enter them.

It does not show a fee where no rate was entered [src: app/src/Register.php:34].

It does not file anything, and it is not advice. It produces the tonnage a report asks for from data you supplied.

It does not hide an incomplete register [src: app/src/Register.php:221], and it does not drop a sales row it cannot match [src: app/src/Register.php:229].

It does not send the same reminder twice [src: app/src/Register.php:108].

← Back to Packora · Quickstart · API · Test run

Affiliate program
Recommend tools people own — earn 35% on every sale. 90-day tracking, instant delivery, payouts by Lemon Squeezy.
Become an affiliate →