A complete double-entry accounting system for Larapen. Manage multiple companies, localized charts of accounts (17 international standards), journals, fiscal years, partners, taxes, bank reconciliation, recurring entries, and generate financial reports, including the French FEC export.
Multi-Company
Manage separate legal entities under one installation. Each company has its own chart, journals, partners, and fiscal years, isolated by a global query scope.
17 Chart Templates
Ship-ready charts for PCG (FR), SYSCOHADA, US/UK/CA GAAP, SKR04 (DE), PGC (ES), PCMN (BE), SNC (PT), RGS (NL), Swiss OR, CGNC (MA), SCE (TN), AASB (AU), IFRS, and more.
Double-Entry Enforcement
Every journal entry must balance before it can be posted. Draft / Posted / Reversed / Cancelled lifecycle with full audit of who posted and when.
Fiscal Years & Period Locking
Auto-generate monthly periods from fiscal year boundaries. Lock or close periods and years to prevent further posting.
Bank Reconciliation
Import bank statements, match lines to journal entries in a two-column workspace, and track system vs. statement balances.
Recurring Entries
Template-based recurring postings (daily, weekly, monthly, quarterly, yearly) with optional auto-post and a daily scheduler.
Financial Reports
Trial Balance, General Ledger, Balance Sheet, Income Statement, and Journal Book. All filter by date range and respect the active company.
Multi-Currency
Currency and exchange rates captured at company, account, journal, partner, bank account, entry, and line level.
FEC Export
Legal French “Fichier des Écritures Comptables” export (TSV, 18 columns) per Arrêté du 29 juillet 2013.
Use Cases
Small Business Bookkeeping
Run a single company with the chart of accounts matching your country (PCG, GAAP, HGB, etc.). Record invoices, payments, and expenses through journals; let the system enforce balanced entries and period locks at month/year end.
Multi-Entity Group
Consolidate several legal entities in one installation. Switch between companies from the top bar; each
company is fully isolated via the company_id scope. Users can be assigned to specific
companies, or granted manage-all access.
French Regulated Accounting
Run a PCG chart, store all entries as draft then post them, lock fiscal periods at year-end, and generate the FEC export for tax inspections.
SYSCOHADA (OHADA) Accounting
Benin, Côte d'Ivoire, Senegal, and other OHADA member countries ship with the full SYSCOHADA révisé chart (9 classes) and can record entries in XOF/XAF with the appropriate tax codes.
Bank Reconciliation Workflow
Upload a bank statement, let staff match transaction lines to journal lines in the reconciliation workspace, and produce a reconciliation record that shows system vs. statement balance with the exact difference.
Requirements
- Larapen CMS v1.0.0 or later
- PHP 8.3+
- MySQL 8.0+
- Core
users,countries, andcurrenciestables must exist ext-bcmathrequired for balance comparisons
Installation
Step 1: Upload the Add-on
In the admin panel, go to Admin → Extensions → Add-ons and click the Upload Add-on button. Select the add-on’s ZIP file: the system extracts it automatically and the add-on appears in the installed add-ons list.
Step 2: Activate the Add-on
Find Accounting in the list and click Activate. Its migrations, seeders (if any) and permissions are set up automatically.
Step 3: Configure
Navigate to Accounting → Companies → New Company to create your first company. Choose a chart template, set the default currency, and save: the chart of accounts is seeded automatically from the selected template. Then review Accounting → Settings to tune fiscal-year rules, numbering sequences, and posting controls. See Configuration.
Step 4: (Optional) Schedule the Recurring Entry Command
The service provider registers accounting:generate-recurring to run daily at 03:00.
Make sure Laravel's scheduler is wired up to cron:
* * * * * cd /path-to-your-project && php artisan schedule:run >> /dev/null 2>&1
Purchase Code (License Key)
Accounting is sold as a separate product, so it has its own purchase code (license key), distinct from the purchase code of the main application and from the one of every other add-on. You are asked for it when you activate Accounting in Admin panel → Add-ons.
Our products are sold on three platforms. The way you receive a purchase code depends on where you bought the product.
| Platform / Marketplace | How you get the purchase code | Where to find it again |
|---|---|---|
| bedigit.com Store In-site purchase (Shop) |
Generated automatically when the order is paid, then sent by email, either in its own license email, or inside the order confirmation email. | My Account → My Licenses on bedigit.com |
| Gumroad | Created as soon as Gumroad notifies us of the sale, then sent in a separate email, in addition to the Gumroad receipt. | The license email, your Gumroad Library, and My Account → My Licenses on bedigit.com |
| Envato Market CodeCanyon |
Issued by Envato, not by us, and never sent by email: you download it yourself from your Envato account. | Envato account → Downloads → License certificate & purchase code |
1. bedigit.com Store (in-site purchase)
- As soon as the order’s payment status becomes Paid, a license key is generated automatically for every licensed item in the order (one key per purchased unit: buying 3 units gives 3 distinct keys).
- It is emailed to the address used on the order, either in a dedicated license email or inside the order confirmation email. Check your inbox and your spam / junk folder.
- The key stays available in your account under My Account → My Licenses. Keys are masked in the list; open the license detail page to reveal and copy the full key, see the domains it is activated on, and deactivate a domain to free an activation slot.
- The matching invoice is under My Account → My Orders.
2. Gumroad
- A Gumroad purchase produces two separate emails: the Gumroad receipt (sent by Gumroad, giving access to the files) and a license key email (sent by bedigit.com) that contains your purchase code.
- The license key email is generated as soon as Gumroad notifies us of the sale, so it normally arrives within seconds of the payment. Here too, check your inbox and your spam / junk folder.
- When the Gumroad product uses Gumroad’s own license-key feature, the same key also appears in your Gumroad receipt and under Library → your purchase on gumroad.com.
- Use the same email address on bedigit.com as on Gumroad: your keys are then linked to your account automatically and listed under My Account → My Licenses, even if you register after the purchase. You can also add a Gumroad key manually from My Account → My Gumroad Licenses.
3. Envato Market (CodeCanyon)
- Envato purchase codes are issued and delivered by Envato Market, never emailed by us, so there is nothing to look for in your spam folder: you retrieve the code from your Envato account.
- Log in to your Envato / CodeCanyon account, open the Downloads page, find the item, and choose License certificate & purchase code from the Download dropdown. The code is written in that certificate.
- An Envato purchase code looks like
12345678-90ab-cdef-1234-567890abcdef(8-4-4-4-12 characters). It never changes, and renewing item support does not issue a new one. - Official Envato article: Where Is My Purchase Code?
Configuration
The add-on ships with config/accounting.php. Each key can be overridden from the environment
or by adjusting the config file directly.
| Key | Description | Default |
|---|---|---|
default_standard |
Accounting standard assigned to a new company when none is specified. | generic |
default_currency |
Fallback currency for new companies and entries. | USD |
decimal_precision |
Number of decimal places displayed in reports and forms. | 2 |
account_code_padding |
Width used when zero-padding account codes. | 8 |
allow_post_in_closed_period |
When true, entries can be posted into locked/closed periods. |
false |
entry_reference_format |
Template for auto-generated entry references. | JE-{year}-{seq:6} |
standards |
Array mapping standard codes (e.g. pcg, gaap_us) to their display name, country, currency, and chart seeder class. |
17 entries |
First Steps
- Create a company and pick the chart template that matches your jurisdiction.
- Review your chart of accounts: hide unused accounts, adjust code ranges, or add custom accounts.
- Create a fiscal year. Monthly periods are generated automatically from its start/end dates.
- Create journals for each book (Sales, Purchase, Bank, Cash, General, Adjustments…). Many templates seed these already.
- Add tax codes (VAT, GST, withholding, etc.) and link them to their VAT payable / receivable accounts.
- Add partners (customers, suppliers, employees).
- Record your first journal entry and post it when you are confident the debits and credits balance.
Admin: Companies
The Companies page (Accounting → Companies) manages legal entities tracked in the system. Companies are not subject to the active-company scope: authorized users can view the full list regardless of which company they are currently operating under.
Creating & Editing Companies
The form is organized into tabs:
- General: name, slug, legal name, tax ID, registration number, country, currency, fiscal year start month, chart template, lock date, active/default flags.
- Address: street, city, state, postal code, country code.
- Defaults: default accounts for retained earnings, sales, purchase, bank, receivable, payable, VAT receivable, VAT payable.
- Users: assign users to the company (with a favorite flag per user).
accounting_accounts for that company.
Assigned Users
The Users tab shows all members currently able to work inside the company. Use the Assign user field (Select2 autocomplete) to add a new user; the Revoke action removes them. All updates are AJAX and refresh the card in place.
A user must either be assigned to a company or hold the accounting.companies.manage-all
permission to see accounting data.
Switching Between Companies
Users with the accounting.companies.switch permission can change their active company from
the top bar. The chosen company is persisted in session and bound via the
CompanyContext singleton: subsequent queries automatically filter by it.
Admin: Chart of Accounts
The Chart of Accounts page (Accounting → Chart of Accounts) shows the full hierarchy of accounts for the active company.
Account Fields
| Field | Notes |
|---|---|
code | Account number (e.g. 411, 512, 707). Unique within the company. |
name | Account description (e.g. “Accounts Receivable”). |
type | Asset, Liability, Equity, Income, or Expense. |
subtype | Optional finer grouping (e.g. current/non-current). |
parent | Parent account for hierarchical charts. |
is_group | Header account: never postable directly. |
is_reconcilable | Can be matched against bank statement lines. |
allow_manual_entries | Disable to force postings through services only (e.g. system-generated VAT accounts). |
currency_code | Override the company currency for this account. |
opening_balance | Initial balance carried into the first fiscal year. |
Import / Export
Accounts can be exported to CSV/Excel and re-imported to bulk-update the chart. An import template (with header row and sample rows) is available via Accounts → Download import template.
Admin: Journals
Journals group related entries. Each journal has its own auto-incremented sequence used to generate
entry references (e.g. SA-2024-000042).
| Field | Notes |
|---|---|
code | Short journal identifier (e.g. SA, PU, BA). |
name | Display name (Sales Journal, Purchase Journal, Bank Journal…). |
type | sales / purchase / bank / cash / general / opening / closing / adjustment. |
sequence_prefix | Optional prefix for generated references. Falls back to the journal code. |
default_debit_account_id / default_credit_account_id | Accounts auto-selected in the entry form for this journal. |
Admin: Tax Codes
Tax codes (VAT, GST, sales tax, withholding…) can be attached to journal lines to track indirect tax. Each tax code is linked to one or two accounts: a collected account (output tax) and a paid account (input tax).
Tax codes are scoped per company and per country. Their rate is stored as a decimal
(e.g. 0.2000 for 20%).
Admin: Partners
Partners are customers, suppliers, employees, and other parties referenced in journal entries. The partner form captures contact information, tax IDs, and default receivable/payable accounts.
Create / Edit Modal
- Code: unique partner code (e.g.
CUST-001,SUP-012). - Name: display name.
- Type: Customer, Supplier, Both, Employee, Other.
- Tax identifier, Registration number.
- Address, Country, Currency (Select2).
- Receivable account / Payable account: overrides the company defaults for this partner.
Import / Export & Bulk Actions
Partners support CSV/Excel import/export, bulk delete, and trash/restore.
Admin: Fiscal Years & Periods
A fiscal year has a start date, end date, and a status (Open, Locked, Closed). On creation, the add-on auto-generates 12 monthly periods between those two dates.
Status Transitions
- Open: entries can be posted freely.
- Locked: no new postings unless
allow_post_in_closed_periodis enabled. - Closed: the Close action cascades to all periods. Admins receive a Period Closing notification.
lock_date acts as a global cutoff for all postings before that date.
Admin: Journal Entries
The Journal Entries page (Accounting → Journal Entries) is the main workbench for recording transactions.
Entry Form
| Field | Notes |
|---|---|
journal | Which book the entry belongs to. |
entry_date | Transaction date. Used to resolve the fiscal period. |
reference | Auto-generated from the journal's sequence. Editable if you need to keep an existing numbering. |
description | Free-text narrative. |
external_reference | Invoice #, PO #, receipt #, etc. |
currency_code / exchange_rate | Override the company currency and rate. |
lines | At least two lines required. Each with account, optional partner, optional tax code, and a debit OR credit amount. |
Entry Lifecycle
- Draft: fully editable, deletable. Shown with a grey badge.
- Posted: immutable. Must have balanced debits / credits.
- Reversed: a reversal entry has been generated and posted.
- Cancelled: manually discarded without a reversal.
Posting
Click Post on a draft entry to move it to Posted. The service verifies:
- Status is Draft.
- Debits equal credits (bcmath comparison).
- The entry's period is not locked (unless the config override is enabled).
If validation fails the admin sees an error message; unbalanced drafts also generate a database notification for admins (Unbalanced Entry Notification).
Reversal
Posted entries cannot be edited, but they can be reversed. The reverse action:
- Creates a new entry in the same journal with debits and credits swapped.
- Assigns a fresh reference from the journal sequence.
- Posts the reversal.
- Flags the original entry as Reversed and links
reversed_entry_id.
Bulk Actions
Entries support bulk delete (draft only), CSV/Excel export, and CSV/Excel import. Import rejects rows that would produce unbalanced entries.
Admin: Recurring Entries
Recurring entries generate a new journal entry on a schedule (rent, depreciation, subscriptions…).
| Field | Notes |
|---|---|
name | Template name (“Monthly Office Rent”, “Annual Software Licences”). |
journal | Journal used for generated entries. |
recurrence_period | Daily, Weekly, Monthly, Quarterly, Yearly. |
interval_count | Repeat every N periods (e.g. 2 for bi-monthly). |
start_date, end_date | Window during which the template is active. |
next_run_date | When the next entry will be generated. Advanced automatically. |
auto_post | If enabled, generated entries are posted immediately. |
template_lines | Debit/credit lines stored as JSON; copied verbatim into each generated entry. |
A daily scheduled command, accounting:generate-recurring, runs every day at 03:00 and
processes all templates whose next_run_date is today or earlier. You can also trigger a
template manually via the Run now action.
Admin: Bank Accounts
Bank accounts link a bookkeeping account (e.g. 512: Banque) to real banking details
(bank name, IBAN, BIC, currency, opening balance). An optional default journal is used when auto-posting
reconciled entries.
Admin: Bank Statements
A bank statement represents a periodic summary from the bank. It has a reference, a statement date, period start/end, opening/closing balances, and a list of statement lines (transaction date, amount, description, optional partner).
Bank statements live as Draft until posted. Posting finalizes the statement and enables matching in the reconciliation workspace.
Admin: Reconciliation
The reconciliation workspace (Reconciliation → Open a statement) displays bank
statement lines on one side and unmatched journal lines on the other. Match them line-by-line; each
match stores a shared reconciliation_ref on both the journal line and the bank statement
line. A reconciliation record tracks the system vs. statement balance with the calculated
difference.
If the difference is zero, the reconciliation status becomes Balanced. Otherwise it remains Draft until investigated.
Financial Reports
All reports accept optional date range filters and respect the active company. Access them via Accounting → Reports.
Trial Balance
Lists every active account with total debits, total credits, and the resulting balance. Totals at the
bottom must equal: the is_balanced flag tells you at a glance.
General Ledger
Per-account detailed listing of every posted journal line with a running balance. Useful for auditing or investigating a specific account.
Balance Sheet
Assets, Liabilities, and Equity grouped by type at a point in time. P&L accounts are implicitly closed to the configured retained earnings account.
Income Statement (P&L)
Revenue and expenses over a period, with net income at the bottom.
Journal Book
Transactions grouped by journal with full entry and line detail. Matches the French “livre journal” requirement.
FEC Export
French businesses are required to produce a Fichier des Écritures Comptables on demand for the tax administration. The built-in FEC export generates a tab-separated file with 18 columns per the Arrêté du 29 juillet 2013:
JournalCode,JournalLibEcritureNum,EcritureDate,EcritureLib,ValidDateCompteNum,CompteLib,CompAuxNum,CompAuxLibPieceRef,PieceDateDebit,CreditEcritureLet,DateLet(reconciliation)Montantdevise,Idevise(foreign currency)
Only Posted entries are included. The date range filter defines the fiscal period exported.
Download requires the accounting.reports.export-fec permission.
Accounting Standards
When creating a company you pick one of the packaged chart templates. The matching chart seeder runs and populates the chart of accounts. All 17 templates are ready out of the box:
| Code | Standard | Country | Currency |
|---|---|---|---|
generic | Generic framework | - | USD |
pcg | Plan Comptable Général | France | EUR |
syscohada | SYSCOHADA Révisé | OHADA (Benin, Senegal…) | XOF / XAF |
gaap_us | US GAAP | United States | USD |
gaap_uk | UK GAAP / FRS 102 | United Kingdom | GBP |
gaap_ca | ASPE / IFRS | Canada | CAD |
skr04_de | SKR04 / HGB | Germany | EUR |
pgc_es | Plan General de Contabilidad | Spain | EUR |
pcmn_be | PCMN | Belgium | EUR |
cc_it | Codice Civile | Italy | EUR |
snc_pt | SNC | Portugal | EUR |
rgs_nl | Referentie Grootboekschema | Netherlands | EUR |
or_ch | Swiss Code of Obligations | Switzerland | CHF |
cgnc_ma | CGNC | Morocco | MAD |
sce_tn | SCE | Tunisia | TND |
aasb_au | AASB | Australia | AUD |
ifrs | IFRS Generic | International | - |
Multi-Currency
Every level of the data model can override currency and exchange rate:
- Company reporting currency.
- Per-account override (e.g. a GBP bank account inside a EUR company).
- Per-journal currency.
- Per-partner currency (used when creating invoices).
- Per-bank-account currency.
- Per-entry
currency_code+exchange_rate. - Per-line
amount_currency,currency_code, andexchange_rate.
The FEC export surfaces Montantdevise and Idevise for foreign-currency
lines.
Notifications
The add-on ships two notification types, both registered with the core notification system. Admins manage recipients and channels from Admin → Settings → Notifications.
| Key | Channels | Trigger | Forced? |
|---|---|---|---|
accounting_period_closing |
mail, database | Fiscal year closed | No (user can opt out) |
accounting_unbalanced_entry |
database | Draft entry fails post due to imbalance | Yes (cannot be disabled per-user) |
Trash & Soft Delete
Companies, accounts, partners, and journal entries use soft-delete. Deleted records land in the corresponding Trash page (e.g. Accounting → Partners → Trash). From there:
- Restore a single record or bulk-restore several.
- Permanently delete (force-delete) individual records, bulk, or empty the trash entirely.
Journal entries are only deletable while in Draft status. Posted entries must be reversed instead.
Updating
- Replace the
extensions/addons/accountingfolder with the new version. - Run
php artisan migrate --path=extensions/addons/accounting/database/migrationsto apply any new migrations. - Run
php artisan config:clear && php artisan view:clear. - If theme assets changed, run
npx vite build.
Uninstallation
Switching an add-on off without losing anything is a deactivation: go to Admin panel → Add-ons, find Accounting and click Deactivate.
- Its routes, views, admin menu entries and permissions stop being registered, and its front-end pages stop answering.
- Its database tables and all the data they hold are kept, and its files stay under
extensions/addons/accounting/. Nothing is deleted. - The purchase code recorded at activation is kept too, so activating the add-on again does not ask for it.
- Deactivation is refused while another active add-on depends on this one: deactivate that add-on first.
Click Activate on the same card to switch it back on. Pending migrations are re-run, assets are republished, and the add-on picks up exactly where it left off.
Removing
Removing is permanent and destroys the add-on's data. The Remove button only appears on a deactivated add-on, so removal is always two steps:
- Deactivate Accounting (see Uninstallation).
- Click Remove on its card and confirm the prompt.
The admin panel then, in one pass:
- runs the add-on's uninstall hook, if it ships one, while its code is still on disk;
- revokes the permissions declared in its
addon.json; - rolls back its migrations (this drops its database tables and every row they hold) and purges its entries from the
migrationstable, so a later reinstall migrates from scratch; - deletes its published assets:
public/addons/accounting/,public/vendor/accounting/andstorage/app/public/addons/accounting/; - deletes the add-on directory
extensions/addons/accounting/; - deletes its row in the
addonstable (the recorded purchase code goes with it) and clears the application cache.
Removal is refused, with an explanatory message and before anything is destroyed, when the add-on is still active, when another active add-on depends on it, or when the web server (PHP) user cannot delete extensions/addons/accounting/. In that last case, give that user write permission on the directory and on its parent, then try again.
Deleting the folder over FTP or SSH is not equivalent: the add-on's tables, its entries in the migrations table and its addons row are all left behind, and its card stays in the list. Use Remove in the admin panel instead.
Troubleshooting
“No active company” when opening an accounting page
- The current user has no assignment and no
accounting.companies.manage-allpermission. - Assign the user to at least one company in Companies → Users tab.
“Entry is not balanced” when posting
- Debits must equal credits to the last decimal (
bccomp, 4 decimal places). - Watch for rounding differences with foreign currency conversions.
“Period locked” when posting
- The entry date falls inside a Locked or Closed period.
- Either move the entry date to an open period or reopen the period (requires
accounting.fiscal-years.edit). - As a last resort, set
allow_post_in_closed_periodtotruein the config.
Duplicate reference error on Reverse
- Happens if the journal's
next_sequence_numberis out of sync with existing entries (typically after a manual import). The observer self-heals by takingMAX(reference) + 1, but you can also reset the counter manually in the Journal edit form.
Recurring entries not generating
- Check that Laravel's scheduler is wired up in cron (
schedule:runevery minute). - Ensure the template is Active and its
next_run_dateis in the past. - Run
php artisan accounting:generate-recurringmanually to see errors.
FEC export returns no rows
- Only Posted entries are included. Verify your date range covers posted entries.
- Confirm the active company has the
fec_country_codeset (FR).
Accounting v1.0.0: Part of the Larapen CMS platform.
© BeDigit. All rights reserved.