Payday Super timing
+----------------------------------------------------------------------+
| Payday Super timing |
+----------------------------------------------------------------------+
| SG charge and due dates since 1 July 2026 |
+----------------------------------+-----------------------------------+
| DR what it gives you | CR what it needs |
+----------------------------------+-----------------------------------+
| due date per payday event | payroll export CSV |
| notional earnings and uplift | fund receipt dates |
| audit trail per employee | national holiday calendar |
+----------------------------------+-----------------------------------+
Distribution payday-super-checker, import package paydaysuper, command payday-super-check.
Experimental review aid. Not a compliance determination. Check Australian super contributions against the payday-super deadlines and produce an experimental SG-charge estimate for lines that the supplied facts establish as late.
Since 1 July 2026, super is generally due within 7 business days of each payday
instead of quarterly. A missed deadline can create an SG shortfall, notional
earnings and administrative uplift; the ATO makes the assessment. This tool
reviews a CSV from payroll, clearing-house and fund records. Version 0.1.7 refuses or marks UNKNOWN where the supported checks
cannot establish the result. Version 0.1.6 assumes full receipt when a
fund-receipt date has neither matched_amount nor remitted_amount; its caveat
discloses that assumption. Supply and reconcile the receipt amount before relying
on an ON_TIME result. See release status.
The australian-accounting repository contains the maintained source. The payday-super-checker distribution, payday-super-check command and paydaysuper import package remain compatibility identifiers.
Built by Ryan Duguid, a provisional member of Chartered Accountants ANZ. Written independently, in his own time and on his own equipment.
No-install explainer: When is payday super actually due. From an AI coding agent, run the same engine through aus-accounting-mcp.
Citation: CITATION.cff.
Release status and examples
This documentation describes checker 0.1.7. See release notes for the receipt-amount migration and workbook corrections. Check PyPI and GitHub releases for available distributions; a checkout version alone does not establish publication.
aus-accounting-mcp 0.2.4 pins checker 0.1.6, so publishing checker 0.1.7
does not update that MCP release. The monorepo workspace substitutes the
checked-out engine source when testing. Check the installed engine version
when comparing CLI and MCP results.
The quick trial below deliberately stays pinned to 0.1.4. The historical public evaluation stays pinned to 0.1.3. Neither is a claim about the latest release. Evidence packs are available from checker 0.1.4; 0.1.5 adds exported join warnings. The frozen PyPI 0.1.6 description still links release 0.1.4 and calls evidence packs unreleased. Editing this README does not change that published metadata. The 22 September verification records the package, MCP and workbook results separately.
Try one contribution without cloning
With uv installed, download the synthetic CSV as timely_remittance_no_receipt.csv. Open a terminal in that folder and run:
uvx --from payday-super-checker==0.1.4 payday-super-check timely_remittance_no_receipt.csv --as-at 2026-08-20 --confirm-remittance-only -o payday-report.csv
The pinned PyPI package writes payday-report.csv in that folder, replacing that file if it exists. Expected result: one AT_RISK contribution, due 2026-08-17, with exit 0. The $120 contribution was remitted on 14 August, but no fund receipt is recorded as at 20 August.
--confirm-remittance-only acknowledges that gap; it does not prove timely receipt. Omit the flag to get the same verdict with exit 2 and a request to resolve or acknowledge the missing evidence. Obtain fund receipt evidence before closing the exception.
The recorded public evaluation uses release 0.1.3 and preserves its original commands and expected exit codes. This quick trial uses release 0.1.4.
Quick proof
The card comes from the fabricated sample and links to the complete console transcript. Re-run the sample and confirm that both committed proof files are current:
python tools/render_quick_proof.py --check
Excel workbook
No Python? workbooks/payday-super-checker.xlsx
implements the 0.1.7 review in ordinary worksheet formulas: paste the canonical
contributions register, set the as-at date, and read the deadline, verdict,
shortfall, notional earnings and SG charge estimate range per line, with the
0.1.7 checker's UNKNOWN outcomes preserved. The tagged 0.1.6 workbook
still assumes full receipt without an amount and extrapolates beyond its GIC
table, unlike the 0.1.6 CLI default. Use the version-specific limits in
workbooks/README.md. It is macro-free, needs desktop Excel for
Microsoft 365 or Excel 2024, and is held to this engine's answer by
tests/test_workbook.py. See workbooks/README.md.
Install
Python 3.10 or later. No runtime dependencies.
git clone https://github.com/ryanduguid/australian-accounting.git
cd australian-accounting/packages/payday-super-checker && pip install .
Cloning first means you have the sample file the next command uses. To skip
the clone, pip install payday-super-checker installs the tool alone from
PyPI. Use the synthetic CSV above for a first run before preparing your own input.
Before you run
Gather these facts first. The 0.1.7 checks can refuse or mark UNKNOWN
when required evidence is missing. The published receipt-amount exception is
described under release status.
| Fact | Where it comes from | Why |
|---|---|---|
| Payroll export | Your payroll system | The payday (the day you actually paid the wages) and the operator-determined SG amount per employee. Apply regulations 11 and 12 and filter out salary sacrifice before supplying the amount |
| Super payment export | Your payroll or clearing-house portal | The day you sent the money. This is the remitted date; on its own it can only give AT_RISK |
| Fund receipt dates | Your clearing house's per-contribution settlement or status report, or the fund's own contribution history | The law tests receipt by the fund. The supported export profiles do not establish this date. Add separate receipt evidence before treating any verdict as final |
| Holidays coverage | The bundled calendar, complete through 31 August 2027 | Deadlines past that horizon fail closed until you supply later official dates in a reviewed --holidays-override file with verified_until |
Use
Review the remittance-versus-fund-receipt boundary with the fabricated Payday Super evidence evaluation.
Start with the sample that has no transition-period contributions. This command runs to a verdict with no confirmation flags:
payday-super-check examples/sample_payrun_no_transition.csv --as-at 2026-09-10
payday-super-checker: 7 contribution lines, as at 2026-09-10
ON_TIME: 3 AT_RISK: 1 LATE: 1 UNPAID: 1 UNKNOWN: 0 SKIPPED: 1
Lines with exposure (experimental estimates, largest first):
row 5 QE day 2026-08-06 due 2026-08-17 UNPAID, 24 days late to as-at date (nothing applied to this payday)
shortfall $780.00 notional earnings $5.88 experimental SG charge estimate $785.88 - $1257.41
row 3 QE day 2026-08-06 due 2026-08-17 LATE, 17 days late to fund receipt
super $540.00 (received, so the shortfall is nil) notional earnings $2.88 experimental SG charge estimate $2.88 - $4.61
Total across 2 line(s): shortfall $780.00, notional earnings $8.76,
experimental estimated SG charge $788.76 - $1262.02.
The second sample, examples/sample_payrun.csv, contains contributions from
the 1 to 28 July 2026 transition period, and running it the same way stops
before writing a verdict:
payday-super-check examples/sample_payrun.csv --as-at 2026-08-10
That stop is the tool working as designed. LCR 2026/1 applies 1 to 28 July 2026
contributions first to any employee shortfall for the quarter ended 30 June
2026, and this file cannot calculate those old-regime balances. The tool asks
for --confirm-transition-allocation. Do not copy that flag mechanically:
use it only after you have reconciled every affected employee. The
confirmation is recorded in the report.
payday-super-check examples/sample_payrun.csv --as-at 2026-08-10 --confirm-transition-allocation
payday-super-checker: 10 contribution lines, as at 2026-08-10
ON_TIME: 5 AT_RISK: 1 LATE: 2 UNPAID: 1 UNKNOWN: 0 SKIPPED: 1
Lines with exposure (experimental estimates, largest first):
row 5 QE day 2026-07-09 due 2026-07-20 UNPAID, 21 days late to as-at date (nothing applied to this payday)
shortfall $780.00 notional earnings $5.15 experimental SG charge estimate $785.15 - $1256.24
note: the deadline passed on 2026-07-20 and no remittance or fund-receipt date is recorded...
row 3 QE day 2026-07-09 due 2026-07-20 LATE, 15 days late to fund receipt
super $540.00 (received, so the shortfall is nil) notional earnings $2.54 experimental SG charge estimate $2.54 - $4.07
Total across 3 line(s): shortfall $780.00, notional earnings $8.07,
experimental estimated SG charge $788.07 - $1260.92.
Both output blocks above are abridged: the real runs list every exposed line and then a page
of assumptions. The console deliberately identifies an exposed record by its input row
rather than its employee identifier, so redirected output does not place payroll
identifiers in process logs. Use that row number to find the full record in
report.csv.
Full detail goes to report.csv: due date, which deadline rule applied, days late, the final shortfall after any offset, notional earnings, best and worst case uplift, and every warning that applies to that line.
The remittance-versus-fund-receipt boundary
examples/sample_remittance_only.csv isolates the missing fund receipt date
in the supported export profiles. Every line in it was remitted on or before its own
deadline, and every fund_received_date is blank, as in the supported
vendor imports. Nothing in the file is late, and nothing in it can
be proved on time:
payday-super-check examples/sample_remittance_only.csv --as-at 2026-09-10
payday-super-checker: 4 contribution lines, as at 2026-09-10
ON_TIME: 0 AT_RISK: 4 LATE: 0 UNPAID: 0 UNKNOWN: 0 SKIPPED: 0
This file cannot produce ON_TIME: no in-scope positive row has a fund-receipt date on or before the as-at date. Fill fund_received_date from the clearing house or fund, then rerun. To accept remittance-only AT_RISK results after that gap is understood, pass --confirm-remittance-only. No payroll payment, lodgment or accounting decision is made by this tool.
4 line(s) remitted by the deadline but with no fund-receipt date. The statutory timing test turns on receipt by the fund, not the day you paid, and clearing-house transit time is the employer's risk.
That run exits 2. There is no exposure in the file and no deadline the calendar could not decide, so the missing receipt date is the only thing holding the run above zero. Confirming that you accept a remittance-only review exits 0 and leaves every verdict where it was:
payday-super-check examples/sample_remittance_only.csv --as-at 2026-09-10 --confirm-remittance-only
payday-super-checker: 4 contribution lines, as at 2026-09-10
ON_TIME: 0 AT_RISK: 4 LATE: 0 UNPAID: 0 UNKNOWN: 0 SKIPPED: 0
Operator confirmed remittance-only review: no in-scope positive row has a fund-receipt date on or before the as-at date, so this file cannot produce ON_TIME. The confirmation is recorded; fill fund_received_date from the clearing house or fund before treating a verdict as final.
4 line(s) remitted by the deadline but with no fund-receipt date. The statutory timing test turns on receipt by the fund, not the day you paid, and clearing-house transit time is the employer's risk.
Both blocks are abridged in the same way as the 2 above: the real runs also
print the assumptions page. The flag records that you understand the gap. It
does not turn AT_RISK into ON_TIME, because paying on time is not the
statutory test. Fill fund_received_date from your clearing house or fund and
rerun before treating any verdict here as final.
A receipt date needs an amount
A fund_received_date says when the fund received something. It does not
say how much. On a row with neither matched_amount nor remitted_amount
the checker therefore leaves the line UNKNOWN rather than ON_TIME,
reports the two outcomes it sits between (ON_TIME if the receipt covered
the whole amount, otherwise UNPAID, NOT_YET_DUE or LATE), exits 2 and
names the amount it needs:
row 2 QE day 2026-08-06 due 2026-08-17 super $540.00 UNPAID or ON_TIME
note: the fund receipt dated 2026-08-12 carries no amount: neither matched_amount nor remitted_amount is on this row, so how much the fund received against the $540.00 SG amount is unknown. A receipt date alone is not evidence of a full receipt, so the line is not read as ON_TIME. Supply matched_amount (the amount the fund received for this payday) from the fund or clearing-house confirmation and rerun
A late receipt with no amount is still LATE, but the s 18D reduction of
the final shortfall waits for the amount and the notional earnings run to
the as-at date as a maximum. Files written by import already carry
matched_amount. For a hand-built file, add the remitted_amount and
matched_amount columns and fill matched_amount with the amount the fund
received on each row that has a fund_received_date, as the shipped
examples do. Versions 0.1.6 and earlier read such a row as a
receipt of the whole sg_amount and say so in a caveat.
Build an evidence pack in one command
Available from published checker 0.1.4. The command below runs this checkout; its receipt-amount changes are included in 0.1.7.
From the monorepo root, change into the component and run:
cd packages/payday-super-checker
uv run --locked payday-super-check evidence-pack evaluation/payday_super_evidence/fixtures/timely_remittance_no_receipt.csv --as-at 2026-08-20 -o evidence-pack
This uses the existing checker and practitioner checklist to write 4 files into a new directory:
| File | Purpose |
|---|---|
report.csv |
Existing report fields with the employee identifier column omitted; source row numbers remain |
practitioner-review.md |
Review queue and checklist bound to the exported CSV's SHA-256 |
exceptions.json |
Schema version 1; every non-ON_TIME row, report hash and run context |
decision-log.md |
Blank evidence, decision and practitioner sign-off template |
Record all decisions and practitioner sign-off in decision-log.md. The
checklist links to that record. Standalone review-pack retains its own
sign-off form.
The fabricated example exits 2 with AT_RISK. Remittance does not establish
receipt. Evidence-pack uses the review-pack exit contract: 0 when every row
is ON_TIME, 2 when any row needs review, and 1 on input or write failure.
--confirm-remittance-only records the acknowledgement but does not remove an
exception or clear exit 2. The existing check, import and review-pack commands
retain their exit meanings and report format.
The exported report has 17 columns and its terminal NOTE marker is in row.
It is not input to the legacy 18-column review-pack command or the accounting
review pipeline's PaydaySuper.Report Excel importer; its matching checklist is
already included. Use the ordinary checker report for that existing importer.
No input path or employee identifier is exported in the evidence pack.
Dates, amounts and engine warnings remain, so keep the pack and its original
input in the same approved private workpaper location. Use source row numbers
to reconcile them. The workflow retains missing facts and all review flags;
the human reviewer records evidence and decisions under applicable APES 110 and
TPB obligations. It provides no advice and performs no lodgement or ledger write.
An existing output file, directory or symlink is refused to preserve previous human decisions. The parent directory must exist. All files are rendered before the output directory is created exclusively. Consume the pack only after the command completes; file creation is not a directory-wide atomic transaction. Write failures leave the partial directory for inspection and return exit 1. The command never deletes these files, which another process may have edited. Choose a new directory for the next run. This feature is not in published v0.1.3.
Use an access-controlled parent directory on every platform. Permissions depend on the OS and Python version; older Windows runtimes can inherit the parent's access controls despite the requested directory mode. The command does not configure or audit access controls.
Build a practitioner review pack
Turn the completed checker report into a deterministic Markdown index and sign-off checklist:
payday-super-check review-pack report.csv -o practitioner-review.md
The report argument must be a bare .csv filename in the current directory.
Unlike every other path this tool accepts, review-pack refuses a directory
part: sub/report.csv, ./report.csv and an absolute path are all rejected
with exit code 1. cd to the directory holding the report, or copy it beside
you, and pass the filename alone. The -o output path is unrestricted.
The pack binds itself to the exact report bytes with SHA-256, recounts every
verdict, reconciles the displayed experimental range and puts each non-ON_TIME
row into a human review queue. It refers to the source CSV's row value rather
than copying employee identifiers into Markdown. Keep the source report beside
the pack in the same access-controlled workpaper location: the CSV remains the
row-level evidence.
The consumer fails closed unless the report has the exact current 18-column
contract, valid displayed arithmetic and one final full-width NOTE row. Exit
code 2 means the pack contains at least one non-ON_TIME row; exit code 1 means
the source or output was invalid. A pack with no exception indicators still
requires practitioner sign-off. The command does not advise, correct, pay,
lodge, disclose or turn the checker output into a compliance determination.
Verdicts are ON_TIME, AT_RISK (remitted in time but no fund receipt recorded), LATE, UNPAID (a supported deadline has passed and a full eligible fund receipt is not established, including where there is no receipt or only a partial receipt), UNKNOWN (the verdict is not available) and SKIPPED (defined-benefit interests). LATE and UNPAID both carry experimental exposure figures.
Some UNKNOWN rows are quiet because there is nothing to assess yet: a
supported deadline has not passed, the row carries no SG amount, or a stale
pre-payment is recorded before a supported deadline. Other UNKNOWN rows need
attention and drive exit code 2. This happens when a deadline extends past the
holiday table's complete horizon, including an unfunded row whose deadline may
not have passed, or when an earlier positive row could trigger item 4 but does
not evidence an eligible contribution that was received, legally allocated to
that earlier QE day and on time. These rows get their own console block and the
CSV records conservative outer outcomes in unassessable_between, such as
LATE or ON_TIME, LATE or UNPAID, UNPAID or NOT_YET_DUE, or LATE or AT_RISK. A caveat may name an intermediate outcome where more than 2 remain
possible. Read that column when parsing the file: UNKNOWN alone also covers
nil rows with nothing at risk.
To get a real verdict, enter the missing holidays in a --holidays-override file and add "verified_until": "YYYY-MM-DD" naming the last date you entered them for. The holidays alone are not enough, and that is deliberate: a file holding one 2029 holiday is not a file that has 2029 covered, and treating it as one would silence the warning across every gap it left. Only you know how far you went.
{
"verified_until": "2029-12-31",
"add": [
{"date": "2029-03-30", "name": "Good Friday", "jurisdictions": ["ALL"]},
{"date": "2029-04-02", "name": "Easter Monday", "jurisdictions": ["ALL"]}
],
"remove": []
}
A date on or before a deadline that runs past the calendar's coverage still gets a verdict. A missing holiday can only push the real deadline later, so paying early is provably on time whatever the calendar is missing.
The exit code is 0 when nothing is exposed, nothing is left undecided, and the file can produce an ON_TIME result (or you passed --confirm-remittance-only after accepting that it cannot). It is 2 when any of those is untrue, and 1 on a data or file error, so you can run it from a scheduled job. A file where no in-scope positive row carries a fund_received_date on or before the as-at date is undecided in that sense: vendor imports never write that column, so the advertised 2-command path is remittance-only AT_RISK until you fill the dates. A receipt dated after --as-at counts as absent here, because the run discards it as future and says so in that row's own caveat. Argparse also uses 2 for a bad command line, so a wrapper should check stderr before raising an alarm.
Options
| Option | What it does |
|---|---|
-o, --output |
Where to write the report CSV (default report.csv) |
--as-at DATE |
Measures notional earnings on still-unpaid contributions to this date (default: today, read from the host clock and named in a printed notice). Pass it explicitly in scheduled or CI runs: the host clock's calendar day can differ from the Australian date near midnight, and a verdict can turn on that day |
--assessment-date DATE |
The day the ATO assessed the charge for these paydays. Only eligible contributions received before it can reduce the final shortfall; a part receipt may not clear it. Omit if no assessment has issued |
--map FIELD=COLUMN |
Point one field at your column name; repeatable |
--mapping-file FILE |
Same thing as JSON, see examples/mapping.example.json |
--holidays-override FILE |
Add or remove public holidays from the bundled calendar; its optional verified_until declares how far you have entered them |
--confirm-transition-allocation |
Confirm you reconciled LCR 2026/1 for every contribution dated no later than 28 July 2026: pre-1 July amounts are unused excess and 1 to 28 July amounts remain after any June-quarter employee shortfall |
--confirm-remittance-only |
Confirm you accept a remittance-only review because no in-scope positive row has a fund-receipt date on or before the as-at date. Without this flag that file exits 2: it cannot produce ON_TIME |
Input columns
Required: employee_id, payment_date, sg_amount. Everything else is optional but sharpens the answer.
| Field | Column in the sample | Meaning |
|---|---|---|
employee_id |
employee_id |
Anything that identifies the employee consistently |
qe_day |
payment_date |
The day you actually paid the wages, not the period end or payslip date |
sg_amount |
sg_amount |
Super guarantee for that payment |
remitted |
remitted_date |
Day you sent the money |
remitted_amount |
remitted_amount |
Amount covered by remitted_date. Blank on a dated row means the whole sg_amount was remitted (the operational reading that 9-column files rely on); a value requires remitted_date and cannot exceed sg_amount. This records operational remittance only. It does not reduce a statutory shortfall without an eligible fund receipt |
matched_amount |
matched_amount |
Total contribution amount associated with this payday, capped at sg_amount. The importer writes an explicit amount even when the vendor supplied no payment date: zero for no match, the partial amount for a short match, and the liability for a full or over match. It is not proof of remittance or fund receipt. When you add fund_received_date, it is the amount that date can evidence, and a receipt date with neither this column nor remitted_amount evidences no amount at all. If it is below sg_amount and remitted_date is present, remitted_amount is required |
received |
fund_received_date |
Day the fund received the eligible contribution associated with this QE day. Receipt is necessary for an on-time result; the row association also asserts the contribution was allocable and applied to this QE day under the statutory ordering. The date fixes timing only. The amount it evidences is matched_amount, then remitted_amount for older 10-column partial files; a row with neither amount is left UNKNOWN rather than ON_TIME (versions 0.1.6 and earlier read it as the whole sg_amount) |
join_caveats |
join_caveats |
Optional, appended last. The importer writes the join's structural warnings here, joined with "|", so they travel with the file into the report's caveats column and the evidence pack instead of living only in the console. Blank on a clean join; absent on canonical files from before 0.1.5 |
first_to_fund |
first_contribution_to_fund |
Yes for the first contribution to that fund (new starter, or a fund switch) |
out_of_cycle |
out_of_cycle |
Yes only for an allowance, bonus, commission, loading, payment in advance or back payment made outside an established payment timing, pattern or schedule, where the statutory next-standard-payment conditions are met |
next_standard_qe_day |
next_standard_payday |
The next schedule-consistent day on which the employer actually made a subsequent non-out-of-cycle QE payment. A planned payday or a date after employment ended is not enough |
db_interest |
defined_benefit |
Yes for defined-benefit interests, which are skipped |
Dates read as YYYY-MM-DD, day-first DD/MM/YYYY, or 9 Jul 2026, and a zone-less time component is ignored. A date-time carrying a Z or UTC-offset marker is refused: its as-written day belongs to that zone, and a UTC evening stamp is already the next day in Australia, so keeping the written day could pass a receipt that was actually a day later. Convert it to the Australian local calendar date first. Amounts accept $ and thousands separators, and are read to the cent (ROUND_HALF_UP) at both the import and check boundaries, so the same figure means the same number whichever door it comes through; a non-zero value under half a cent is refused rather than rounded to nothing. Anything unreadable stops the run and names up to 20 bad cells at once, and so does a truncated row, a duplicated column heading, or a mapping that points at a column your file does not have. This experimental review tool refuses facts it cannot safely infer.
The amount column must hold the operator-determined SG amount only. Apply the employee and payment boundaries in regulations 11 and 12, the qualifying-earnings rules, the maximum contribution base and any other relevant facts before supplying it. Salary sacrifice and additional contributions have a different base and deadline, so filter them out. The tool does not classify raw pay, apply regulations 11 or 12, or decide whether a termination payment is qualifying earnings. LCR 2026/D1 remains draft, so those decisions stay human.
Where the fund receipt date comes from. The supported payroll export profiles provide pay and remittance evidence, which is what remitted is for and why those lines come back AT_RISK. They do not establish receipt by the fund. Obtain separate receipt evidence from your clearing house's per-contribution settlement or status report, or the fund's own contribution history. Without it the tool tells you what you sent and when, not what the law tests.
Import from your payroll system
Two commands turn a payroll export and a super payments export into a checked report, with no column mapping to write by hand:
payday-super-check import --payroll "Payroll Activity Details.csv" --super "Superannuation Payments.csv" -o contributions.csv --confirm-statutory-allocation
payday-super-check contributions.csv --confirm-transition-allocation
The second command exits 2 until fund_received_date is filled in, or until
you pass --confirm-remittance-only after accepting remittance-only AT_RISK
results. Do not copy that flag mechanically either.
The first command reads both exports and writes the canonical CSV the second
command checks. Where an employee has more than one in-scope positive payday,
it stops without output unless you pass --confirm-statutory-allocation. Do not
copy that flag mechanically. LCR 2026/2 paragraphs 31 to 33 apply contributions in
fund-receipt order to the earliest QE day with a base or final shortfall. Vendor
exports provide employer payment dates and pay-period labels, not that receipt
order or the assessment facts that can change it. Use the flag only after you
have reconciled every relevant payday, contribution receipt and assessment and
confirmed that the export's periods plus payment-date/row order reproduce the
statutory allocation. The importer allocates a short shared payment to the
earliest covered shortfall; it no longer treats the vendor period end as an
instruction to pay a later QE day first. The confirmation is printed in the
import record.
Profiles ship for Xero Payroll, MYOB AccountRight, MYOB Business and Employment Hero / KeyPay, one profile each for the payroll-activity report and the super-payments report. The importer picks a profile per file by scoring column headings against what it knows. Force one with --vendor xero, --vendor myob-ar, --vendor myob-business or --vendor employment-hero when detection cannot pick, or to skip detection outright.
Every shipped profile is unverified against a real export. Each one's column names come from vendor help documentation, and Xero, MYOB and Employment Hero do not publish an actual column list for these reports, so the first real export you try may match no profile at all. When that happens the importer prints the column headings it found in your file next to the headings each candidate profile wanted. Send both lists back and fixing the profile is a one-line edit to its JSON file, not a rewrite.
The supported export profiles do not establish a fund receipt date. Xero's report gives the date a payment was sent to the fund. MYOB gives a Paid Date. Employment Hero gives a Beam status (Sent to fund, Reconciled, and so on). None of these is the date the fund received the money. The legal deadline tests receipt by the fund, and time in transit through a clearing house is the employer's risk, not the fund's, so a vendor date is a remittance date and fund_received_date is left blank on every row. Fill that column in from your fund or clearing house before treating any verdict from the checker as final. remitted_date is the latest known vendor date for the dated subtotal; an entirely undated match leaves it blank. The Beam status also decides whether the date counts at all: a batch still at Created, Submission accepted or Awaiting payment is money that never left the employer, so its Payment Date is not written as a remittance date and the payday reads as unfunded, with a warning naming the status. A status outside the Beam ladder stops the import rather than being guessed either way.
A mixed dated/undated match uses the latest known date conservatively. If 600.00 of a 1000.00 match has a vendor date and 400.00 does not, remitted_date is the latest known date for the dated subtotal, remitted_amount is 600.00 and matched_amount is 1000.00. An as-at report shows none of the dated subtotal as remitted before the date and only 600.00 on or after it; the undated 400.00 stays operationally unremitted. A dated 999.99 part payment writes 999.99 in both amount fields, leaving 0.01 operationally unremitted. That vendor evidence does not reduce the statutory base or final shortfall by itself: without fund_received_date, the SGC estimate continues to treat the full 1000.00 as unreceived. If an eligible fund receipt is supplied on the row, it can credit at most matched_amount; an on-time partial receipt reduces the base shortfall, while a late partial receipt can reduce only the final shortfall and not the base used for notional earnings. An entirely undated match leaves both remittance fields blank but still writes its total to matched_amount, so adding a later receipt date cannot turn a known partial match into full credit. sg_amount is always the amount owed.
The importer still prints row N: partial: 999.99 of 1000.00 matched and row N: 400.00 of 1000.00 matched has no payment date on record; latest known payment date 2026-07-15. Neither line is ever truncated by the warning cap.
A full financial-year export needs trimming first. The check refuses any file holding a payday before 1 July 2026, because the old quarterly law governs those and this tool does not model it. An export that starts at 1 July 2025 therefore imports fine and then fails the check outright. The import names those rows in a warning and writes them anyway; delete them from the canonical file, or re-export from 1 July 2026, before running the second command.
A bare filename of import does not work. payday-super-check import, run against a file that is genuinely named import with no extension, is read as the import subcommand and fails on the missing --payroll/--super arguments instead of checking the file. payday-super-check import.csv and payday-super-check ./import both check the file as expected; only the exact bare string import is swallowed.
The bare names review-pack and evidence-pack are also reserved subcommands.
For a contribution file with one of those names, use ./review-pack or
./evidence-pack to run the ordinary checker. Qualified paths and .csv filenames
remain unambiguous.
Local file boundary
This is a single-user command-line tool. Its positional input, importer input, mapping, calendar override and output arguments designate files the invoking operating-system account has chosen to read or write; they are not a sandbox. The one exception is review-pack's report argument, which must be a bare .csv filename in the current directory and is opened there. Do not expose the command as a web endpoint, multi-user service, or automation that accepts path values from a less-trusted caller without adding an appropriate safe-root boundary.
Contribution and report outputs must have an explicit .csv filename; the
practitioner pack must have an explicit .md filename. They are staged in the
selected output directory and atomically replace the selected output name. This
means an existing output symlink is replaced rather than followed, and a failed
write does not leave a partial output at that name. Each command refuses an
output path that resolves to a file it reads: for the check, the contribution
CSV, a --mapping-file and a --holidays-override; for the import, both
exports; and for review-pack, the report CSV. A suffix rule does not cover
this on its own, because an input is free to carry the same suffix.
The rules it applies
The enacted framework is the Treasury Laws Amendment (Payday Superannuation) Act 2025 (No 57 of 2025, assent 6 November 2025), the Superannuation Guarantee Charge Amendment Act 2025 (No 58 of 2025), and the regulations registered as F2026L00133, which amend the Superannuation Guarantee (Administration) Regulations 2018; the current 1 July 2026 compilation is F2026C00535. It applies to paydays from 1 July 2026. A primary-source implementation review was completed on 15 August 2026. The review records the exact legislation, final ruling status, holiday authorities, runtime comparison and residual limits. It does not turn this experimental tool into an ATO compliance determination or authorise a release. The 15 August review is the maintained primary-source record.
ATO LCR 2026/1, LCR 2026/2 and LCR 2026/3 were issued on 5 August 2026. LCR 2026/D1 remains draft pending the appeal from Department of Education v Commissioner of Taxation [2026] FCA 898. The tool therefore accepts an operator-provided SG amount and does not decide qualifying-earnings or termination classifications.
The deadline. A contribution is on time only if the fund receives it, with enough information to allocate it, by the end of the seventh business day after the payday (SGAA 1992 s 6(1) 'usual period', s 18C(1)(c)). Paying a clearing house by the deadline does not count, and the ATO's small business clearing house closed on 30 June 2026, so transit time is now the employer's risk. That is why a line with a remittance date but no fund receipt date comes back AT_RISK rather than ON_TIME.
Business days. SGAA s 6(1) defines a business day as any day that is not a Saturday, a Sunday, or a public holiday for the whole of any State, the ACT or the NT. One national calendar applies to every employer: WA Day stops the clock for a Sydney employer. Regional and locally substitutable holidays do not. The Brisbane Ekka, WA's default King's Birthday date and Melbourne Cup Day are therefore business days for this definition. The bundled calendar is complete from July 2026 through 31 August 2027. Business Victoria still lists the exact 2027 grand-final holiday as subject to the AFL schedule, so later deadlines fail closed until that date is officially published or supplied through a reviewed override. Unconfirmed dates do not extend a deadline.
20 business days instead of 7 for the first contribution to a particular fund, whether that is a new starter or an existing employee switching funds (s 18C(2) item 1). Under item 4, a later QE day's deadline can align to an earlier contribution's later end only if that earlier eligible contribution was made and applied under s 18C(1). The checker applies the extension only where the earlier canonical row evidences an on-time fund receipt and thereby asserts the statutory allocation. A positive amount or remittance alone is not enough. If the missing fact could change the verdict, the later row is attention-driving UNKNOWN, not treated as extended. Include each employee's earlier paydays and reconcile their LCR 2026/2 allocation; a single pay run cannot establish the rule.
Out-of-cycle payments can ride a subsequent standard QE payment's window rather than their own (SGAA s 18C(2) item 2 and s 18C(3); final determination F2026L00784). The earlier review called this “LI 2026/20”, but that shorthand is not shown on the Federal Register's as-made page; this project uses the controlling registered identifier and text instead. The final determination covers 6 kinds of qualifying earnings: allowances, bonuses, commissions, loadings, payments in advance and back payments. The employer must have an established timing, pattern or schedule for qualifying-earnings payments, and the payment must fall outside it. It also requires the employer to actually make a subsequent non-out-of-cycle qualifying-earnings payment on the next day consistent with that schedule. A planned next payday, or a termination/final payment with no later payment, does not establish item 2. out_of_cycle=yes without the date of that actual subsequent payment is a hard error. Where both this rule and the new-fund rule apply, the later deadline governs.
When it is late, notional earnings compound daily at the general interest charge rate on the base shortfall for each late-period day on which the final shortfall remains greater than nil (s 19A), and an administrative uplift of up to 60% applies on top. A full late contribution received before the ATO assesses the charge can clear the final shortfall under s 18D, which is why a fully paid-but-late line shows a small experimental estimate rather than the whole contribution. A part late receipt reduces only the final shortfall: it does not retrospectively reduce the base used for notional earnings, and accrual continues while a remainder exists. Pass --assessment-date if an assessment has already issued; a receipt on or after that date does not reduce the final shortfall in this estimate.
The uplift starts at 60% and falls 20 points where the clean-history test is met, and another 40, 35, 30 or 15 points according to voluntary-disclosure timing. For QE days through 30 June 2028, the transitional clean-history lookback begins on 1 July 2026 rather than reaching back a full 24 months. The report shows both ends of the range because the ATO, not this tool, decides which reductions apply. Read the low figure carefully: it assumes both a clean history and a voluntary disclosure lodged within 30 days of the payday, so for an old payday with no disclosure already lodged the real floor is higher.
What it does not do
- Choice loading (25% of contributions paid in breach of choice of fund, capped at $1,200) is not estimated. You cannot see a choice breach in a pay run.
- The maximum contributions base ($270,830 a year per employer for 2026-27) is not applied, because it needs each employee's cumulative earnings for the year. Contributions for people earning above it may show a larger shortfall than the law requires.
- The late payment penalty and interest on an unpaid assessment sit after assessment and are out of scope.
- Exceptional circumstances determinations under s 18C(2) item 3 are not detected. If one covers you, your deadline is later than what you see here.
- Paydays before 1 July 2026 stop the run. Those are governed by the old quarterly law and this tool does not model it.
- Fund deeds, enterprise agreements and awards can require payment earlier than the SG rules. This tool only tests the SG charge.
- Qualifying-earnings and termination classifications are not decided. LCR 2026/D1 remains draft and the input contains an operator-provided SG amount, not raw pay components.
- Assessment rounding is not reproduced. The tool displays report components to cents with
ROUND_HALF_UP; TAA 1953 s 16B applies a 5-cent down-round only to the Commissioner's final assessed SG charge. Exposure figures are experimental estimates.
PCG 2026/1 sets out how the ATO will allocate compliance resources for paydays up to 30 June 2027. Fixing a late contribution quickly lowers the chance of review. It does not remove the liability: the Commissioner has no discretion to waive the charge once a shortfall is known (PCG 2026/1 paragraph 11).
Those are the things the tool never attempts. Separately, LIMITATIONS.md records the cases where it does produce a figure that you should not read at face value, naming what stays correct in each.
Which table produced the interest
exceptions.json in an evidence pack carries a manifest naming the
statutory rate tables the run consumed, each with the SHA-256 of the text that
was read:
"manifest": {
"rate_table_uris": [
{ "uri": "paydaysuper/data/gic_rates.json", "sha256": "243e64b5..." }
]
}
The digest comes from the loader that read the file, not from a later pass
over the directory, and it is taken over decoded text so a CRLF checkout and
an LF checkout of the same reviewed table agree. The prose provenance line in
the report says which quarters the table covers; the digest says whether it is
the same table, which is the question a reviewer reopening the pack months
later actually has. rates.json is not yet listed: its loader returns a bare
dictionary shared by several callers, so carrying its source needs a wider
change than this.
Keeping it current
Everything that goes stale lives in paydaysuper/data/.
gic_rates.json: the general interest charge rate, which the ATO resets every quarter. Each entry records where the figure came from and when that was checked. Update it each quarter. A row whose notional earnings period runs past the last quarter in the file keeps its verdict, its days late and its shortfall, which are decided without a GIC rate, and carries no SG charge estimate: the notional earnings, both uplift figures and both SG charge columns are left empty, and the row's caveat names the last quarter on record. Pass--allow-stale-gicto estimate those days at the last known rate instead; the report then says it did, and the estimate compounds a rate the ATO has not published.rates.json: SG rate, concessional cap, maximum contributions base, per financial year, with the same source and checked-date fields.business_days.json: national non-business days plus the 8 official jurisdiction URLs and their check date. Regenerate withuv run --locked --extra dev --python 3.12 python tools/generate_calendar.py > paydaysuper/data/business_days.json, which uses the lock-pinned development environment, then check every line against those official pages before shipping. Raw generator output deliberately setsverified_untilto 1 July 2026 andofficial_sources.checkedto null; a human reviewer must record the check date and raise the horizon only as far as every jurisdiction's official material supports. Regional, part-day and locally substitutable dates are excluded. Unconfirmed dates are reference-only and do not extend a deadline until an official override confirms them.
Part-day holidays, such as Christmas Eve evening in South Australia, Queensland and the Northern Territory, are treated as business days because applying them as a full day would extend the statutory deadline without authority. Melbourne Cup Day and WA's default King's Birthday date are also business days for this definition because the official pages permit regional substitution, so neither applies throughout its State. The override exists for newly proclaimed whole-of-jurisdiction dates and for an operator who has completed a later official calendar.
Tests
pip install -e ".[dev]"
pytest
The suite pins the ATO's own worked examples: a first payday of 9 July 2026 falling due 7 August 2026, and notional earnings on a payday whose usual period ends 18 June 2027 starting to accrue on 19 June 2027. It also pins the traps that make this hard, including the Ekka staying a business day, deadlines that must not change when you reorder rows in the CSV, and the leap-year divisor in the interest calculation. Test data is synthetic. Never commit client payroll data to this repository; .gitignore blocks the usual formats, case-insensitively.
Disclaimer
This is an educational tool, not tax, legal or financial advice, and using it creates no professional relationship. The ATO assesses the SG charge; figures here are experimental estimates that exclude components listed above. LCR 2026/1, 2026/2 and 2026/3 are final, while LCR 2026/D1 remains draft and may change after the pending appeal. Check anything material against current ATO guidance and calculators, and get advice for your circumstances.
MIT licensed.
Metadata
Release files for payday-super-checker 0.1.7
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| payday_super_checker-0.1.7.tar.gz | 365.2 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| payday_super_checker-0.1.7-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 485.7 kB
Release files / payday_super_checker-0.1.7.tar.gz
| Download URL | payday_super_checker-0.1.7.tar.gz |
|---|---|
| Size | 365.2 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
21e8603eb643ae4399ff67039e03c9f7d0f58354ceefca74a8350fbecb08fd24
|
|
BLAKE2b-256 checksum How to use checksums |
ea4da0e96f9ac5590985100b260294b99efc87f992824bde5cf9df98b7cb7490
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Sep 21, 2026.
Transparency logRelease files / payday_super_checker-0.1.7-py3-none-any.whl
| Download URL | payday_super_checker-0.1.7-py3-none-any.whl |
|---|---|
| Size | 120.5 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
a77e91878572af00404eb0900e97d6f7799b04ee20dcc6e0812f4e1a5f614ca3
|
|
BLAKE2b-256 checksum How to use checksums |
8a9ac579c9b7b5fe94686bdea83c708f80dda1c0b62a2af358156cc9b36ed2ba
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Sep 21, 2026.
Transparency log