Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .github/workflows/lint.yml
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,11 @@ on:
push:
branches:
- main
- australia
pull_request:
branches:
- main
- australia

# Least privilege: linting only needs to read the tree.
permissions:
Expand Down
2 changes: 2 additions & 0 deletions .github/workflows/security.yml
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,11 @@ on:
push:
branches:
- main
- australia
pull_request:
branches:
- main
- australia
# Re-run weekly so newly-disclosed CVEs in unchanged dependencies are caught
# even without a code change. The run history is SOC 2 (CC7.1) evidence that
# we continuously track vulnerabilities.
Expand Down
36 changes: 32 additions & 4 deletions .github/workflows/tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,12 @@ on:
push:
branches:
- main
- australia
pull_request:
branches:
- main
- australia
workflow_dispatch:

# Least privilege: the test job only reads the tree.
permissions:
Expand All @@ -16,8 +19,35 @@ jobs:
ci:
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
php-version: ['8.5']
database: [sqlite, mysql]

# Disposable test database only; never use deployment credentials here.
services:
mysql:
image: mysql:8.4
env:
MYSQL_ALLOW_EMPTY_PASSWORD: 'yes'
MYSQL_DATABASE: lineledger_test
ports:
- 3306:3306
options: >-
--health-cmd="mysqladmin ping --silent"
--health-interval=10s
--health-timeout=5s
--health-retries=12

env:
APP_ENV: testing
DB_CONNECTION: ${{ matrix.database }}
DB_DATABASE: ${{ matrix.database == 'sqlite' && ':memory:' || 'lineledger_test' }}
DB_HOST: 127.0.0.1
DB_PORT: 3306
DB_USERNAME: root
DB_PASSWORD: ''
DB_URL: ''

steps:
- name: Checkout code
Expand All @@ -28,6 +58,7 @@ jobs:
with:
php-version: ${{ matrix.php-version }}
tools: composer:v2
extensions: pdo_mysql, pdo_sqlite
coverage: xdebug

- name: Setup Node
Expand All @@ -36,7 +67,7 @@ jobs:
node-version: '22'

- name: Install Node Dependencies
run: npm i
run: npm ci

- name: Run JS Unit Tests
run: npm test
Expand All @@ -54,7 +85,4 @@ jobs:
run: npm run build

- name: Run Tests
env:
DB_CONNECTION: sqlite
DB_DATABASE: ':memory:'
run: ./vendor/bin/pest
46 changes: 46 additions & 0 deletions docs/australia/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
# Australian support: development status

Australian support is **not implemented or approved for production use**.
This directory records the fork's implementation evidence and open requirements.
It is not tax advice or an ATO certification.

## First milestone: baseline and requirements

- [Code map](code-map.md): verified entry points, risks and existing tests.
- [Requirements register](requirements.md): source-backed specifications and unresolved research.
- [Baseline](baseline.md): reproducible checks, actual results and outstanding gates.

Keep `main` identical to upstream. Integrate small feature branches into
`australia`. Merge upstream through reviewed sync branches; do not routinely
rebase or force-push the published integration branch. Run the complete suite
on MySQL and SQLite after synchronisation, including Canadian and US tests.
Do not auto-deploy upstream updates to live books.

## Implementation order

1. Establish PHP/database baseline, confirm country boundaries and record requirements.
2. Add AU country/defaults and server-side capability restrictions, with CA/US regressions.
3. Add identifiers and effective-dated business registrations.
4. Specify and implement immutable tax facts, precision, GST and invoice output.
5. Implement settlement attribution and auditable BAS/IAS preparation.
6. Validate bank/POS reconciliation, assets, inventory and year-end exports.
7. Implement Australian payroll with specialist-reviewed examples.
8. Add separately authorised STP, super and electronic tax-service integrations.
9. Expand entity, state, award and specialist-industry coverage explicitly.

Every release needs source-to-test traceability, reviewed expected results,
migration/restore checks and a published capability matrix. Digital-service
authorisation is a separate gate from calculation correctness.

No upstream contribution is to be submitted without the owner's approval of
the current upstream CLA. Review PRs in this fork do not request upstream review.
Do not commit real business records, TFNs, credentials or payroll data.

## Next branch acceptance criteria

`au/country-foundation` must cover every `Country` method, tax-authority catalog,
wizard and model defaults, Australian timezones and July financial-year defaults.
It must not enable Canadian payroll, CRA forms, US 1099 or charity receipts for AU.
Inspect existing `JurisdictionProfile` rather than adding a second capability system.
Resolve the legal-link fallback and onboarding binary country selector explicitly.
The baseline PHP gates must be established before claiming this branch is verified.
73 changes: 73 additions & 0 deletions docs/australia/baseline.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
# Baseline evidence

Inspected 2026-09-11 at upstream commit
`c42d49020e3f65d067e88d5a10765a2b629fbc18`.

| Check | Observed result |
| --- | --- |
| Initial worktree | Clean on `australia` |
| JavaScript tests (`npm test`) | 60 passed, 0 failed, 0 skipped |
| Local Node | v24.19.0; CI uses Node 22, so this is not an exact CI reproduction |
| PHP, Composer, Docker, MySQL executables | Not available on the inspected workspace PATH |
| PHP/Pest on SQLite | Not run; awaiting CI/runtime |
| PHP/Pest on MySQL | Not run; awaiting CI/runtime |
| Pint / PHPStan | Not run; awaiting CI/runtime |
| Production asset build | Not run; awaiting installed dependencies |
| Dependency / security checks | Not run; awaiting CI |

The JavaScript result covers the existing arithmetic-input helper, not PHP tax
or payroll calculations. Do not describe the application baseline as passing
until the pending checks have actual successful results attached to a commit.

## CI changes in this milestone

The tests, lint and security workflows now include PRs into and pushes to
`australia`, while preserving `main`. Tests use the committed npm lockfile via
`npm ci` and run independent SQLite and MySQL jobs with fail-fast disabled.
MySQL 8.4 is a disposable CI service; its empty password is not a deployment setting.
The service runs in both matrix jobs for configuration simplicity; SQLite uses
`:memory:` and never connects to it. No publish/deploy workflow is changed.

Only a completed workflow run can demonstrate that these changes work. If a
permission or workflow approval prevents a run, record it and request approval;
do not route around the restriction. Existing failures must be distinguished
from failures introduced by this branch; do not update baselines just to hide them.

## Reproduce on a development machine

Use PHP 8.5, Composer 2, Node 22 and the required PHP extensions. Start with a
fresh clone and no production environment or credentials. Install locked dependencies:

```bash
composer install --no-interaction --prefer-dist --optimize-autoloader
npm ci
```

Prepare a development `.env` from `.env.example`, generate an application key,
and use disposable databases only. Do not run `composer run setup` against a
live deployment: that script performs migrations.

```bash
php artisan key:generate
php artisan config:clear
npm test
npm run build
DB_CONNECTION=sqlite DB_DATABASE=':memory:' DB_URL='' ./vendor/bin/pest
```

On a disposable MySQL instance with an empty-password local root account and a
new database named `lineledger_test` (matching the CI service):

```bash
DB_CONNECTION=mysql DB_HOST=127.0.0.1 DB_PORT=3306 \
DB_DATABASE=lineledger_test DB_USERNAME=root DB_PASSWORD='' DB_URL='' ./vendor/bin/pest
vendor/bin/pint --test
vendor/bin/phpstan analyse --no-progress --memory-limit=1G
composer audit --locked --abandoned=report
npm audit --audit-level=high
```

Feature tests use `RefreshDatabase` and can destroy test data. Never point these
commands at a business database. Keep overrides explicit so local configuration
does not choose the target. Record commit, runtime versions, database version,
test totals, failures and workflow URL when updating this evidence.
57 changes: 57 additions & 0 deletions docs/australia/code-map.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
# Country-specific code map

Targeted inspection at `c42d49020e3f65d067e88d5a10765a2b629fbc18`.
This is an implementation starting map, not an exhaustive security or route audit.
Paths are repository-relative. Entries marked “trace next” have not been proven end to end.

| Area | Entry points | Observed behaviour / next action |
| --- | --- | --- |
| Country identity | `app/Enums/Country.php` | CA/US only; explicit matches must all handle AU; `fromHost` treats non-`.ca` hosts as US |
| Company creation | `app/Models/Company.php` | Canada fallback, January financial year, immutable country; timezone options need AU review |
| Seed defaults | `app/Support/Defaults/CompanyDefaults.php`, `CanadianDefaults.php`, `AmericanDefaults.php` | Reusable country contract; add AU implementation without altering old defaults |
| Wizard account templates | `app/Support/Defaults/ChartTemplateBuilder.php` | Separate creation path; Canada-versus-other share terminology needs explicit AU treatment |
| Tax authorities | `app/Support/Tax/TaxAuthorityCatalog.php` | Exhaustive CA/US match requires AU branch; catalog itself does not create an agency |
| Capability boundary | `app/Support/Jurisdiction/JurisdictionProfile.php`, `app/Enums/JurisdictionCapability.php` | Existing single resolver; payroll/Canadian slips share a Canadian predicate; do not broaden the shared arm when later adding AU payroll |
| Entity filing | `app/Support/Tax/FilingProfile.php` | Canadian return eligibility; retain country guard and introduce distinct AU requirements |
| Legal defaults | `app/Support/Legal/LegalDocuments.php`, `config/app.php` | APP_REGION / hostname resolution; missing marketing URL falls back to Canada; must not silently attach Canadian legal framing to AU |
| Navigation and reporting | `app/Support/Navigation/SidebarNavCatalog.php`, `app/Support/Reporting/ReportCatalog.php` | Country-aware display; trace server-side authorisation independently |
| Payroll portal | `app/Http/Middleware/EnsurePortalAudience.php` | References company payroll capability; test direct links and admin overrides for AU |
| MCP profile | `app/Mcp/Tools/CompanyProfileTool.php`, `app/Mcp/Resources/CompanyProfileResource.php` | Descriptions frame filing as CRA; audit data exposure and capability checks |
| MCP tax preparation | `app/Mcp/Prompts/SalesTaxFilingPrepPrompt.php` | Uses country tax label; label changes alone do not implement BAS |
| Tax computation | `app/Services/Posting/TaxCalculator.php`, `app/Models/TaxCode.php` | Existing discount/markup then additive tax; scaled quantity uses float conversion and truncation; characterise before changing rounding |
| Return preparation | `app/Services/Tax/TaxReturnBuilder.php` | Delegates to report tax lines/totals; not a BAS mapping engine |
| Return lifecycle | `app/Services/Tax/TaxReturnFiler.php` | Local frozen snapshot and filed status; no ATO submission; separate accepted-lodgement evidence required |
| Canadian payroll | `app/Services/Payroll/CalculatePayRun.php`, `PayrollDeductionEngine.php` | Canadian CPP/EI/etc.; AU requires its own calculation implementation and classification rules |
| Tax assets | `app/Services/Tax/CcaCalculator.php` | Canadian tax treatment; no AU tax-depreciation claim |
| Persistence | `app/Services/Backup/BackupTableRegistry.php`, `app/Services/Restore/RowTransformer.php` | Explicit registry/transformation paths; all new tables and rule snapshots need round-trip tests |
| Container publishing | `.github/workflows/docker.yml` | Main/release-tag publishing; not an AU release channel; unchanged in this milestone |

## Existing tests to extend

- `tests/Feature/Companies/CountryEnumTest.php`: currently asserts exactly two countries.
- `tests/Feature/Companies/CountryImmutabilityTest.php`
- `tests/Feature/Companies/JurisdictionDefaultsTest.php`
- `tests/Feature/Companies/CreateCompanyDefaultsCurrencyTest.php`
- `tests/Feature/Companies/CompanyTimezoneTest.php`
- `tests/Feature/Jurisdiction/JurisdictionCapabilityMatrixTest.php`
- `tests/Unit/ChartTemplateBuilderTest.php`
- `tests/Feature/Accounting/TaxCalculatorTest.php`
- `tests/Feature/Accounting/MultiTaxPostingTest.php`
- `tests/Feature/Accounting/TaxReturnFilingTest.php`
- `tests/Feature/Accounting/TaxReturnPaymentTest.php`
- `tests/Unit/Backup/BackupTableRegistryTest.php`
- `tests/Feature/Backup/CompanyExportEndToEndTest.php`

## Trace next before changing accounting code

1. Country selector, wizard step validation, model/API creation and company copying.
2. Every capability's route, action, API/MCP and employee/customer portal checks.
3. All document posters, credits and payment allocation paths; tax-code mutation after posting.
4. Invoice and report PDF templates, foreign-currency conversion and settlement dates.
5. Import/restore validation of country, tax facts and legacy organisation identifiers.
6. Jobs/scheduler and admin overrides that could bypass country capability gates.

Search terms for repeat audits: `Country::`, `address_country`, `APP_REGION`,
`isCanadian`, `CRA`, `1099`, `GIFI`, `CPP`, `EI`, `QPP`, `CCA`, `GST/HST`,
`America/`, `CAD`, `USD`, `fiscal_year_start_month`.
Search hits are leads, not proof of defects. Preserve legitimate CA/US behaviour.
Loading