Billing & Invoicing
Comprehensive billing and invoicing system for Larapen: manage invoices, payments, credit notes, recurring invoices, expenses, product catalog, and quote requests from a single admin panel.
Invoice Management
Create, send, and track invoices with line items, taxes, discounts, and automatic numbering.
Recurring Billing
Set up recurring invoices with flexible frequencies: weekly, monthly, quarterly, or annual.
Quote System
Receive quote requests from visitors, create proposals, and convert accepted quotes to invoices.
Expense Tracking
Track expenses by category with optional approval workflow and receipt uploads.
Credit Notes
Issue credit notes against invoices for refunds and adjustments with full audit trail.
PDF & Public Links
Generate PDF invoices and quotes. Share token-based public links for customers to view and pay.
Use Cases
Freelancer / Consultant
You run a portfolio site on Larapen and need to invoice clients for completed work.
- Create customers for each client with billing addresses and payment terms.
- Add your services to the product catalog (e.g. “Web Development: hourly”).
- Create invoices, attach line items, and send via email with a public payment link.
- Track payments and generate PDF receipts.
Agency with Retainer Clients
You manage multiple clients on monthly retainers and need automated recurring billing.
- Set up recurring invoices for each retainer client with monthly frequency.
- Invoices are generated automatically and optionally sent to the client.
- Track outstanding balances and overdue invoices from the billing dashboard.
Service Business with Custom Quotes
Potential clients submit quote requests through your website before engagement.
- Embed the quote request form on your front-end with categories (e.g. “Web Design”, “SEO”).
- Review requests in the admin panel and create detailed proposals.
- Send the quote via email with a public link. Once accepted, convert to an invoice.
Small Business with Expense Tracking
You need a simple way to track business expenses alongside revenue.
- Organize expenses by category (Office, Travel, Software, etc.).
- Upload receipts and optionally require manager approval.
- View revenue vs. expenses on the billing dashboard.
Requirements
| Requirement | Version |
|---|---|
| Larapen Core | ≥ 1.0.0 |
| PHP | ≥ 8.2 |
| DomPDF | Included via barryvdh/laravel-dompdf |
Installation
Step 1: Place the Add-on
Copy or symlink the billing folder into extensions/addons/billing.
Step 2: Activate the Add-on
Go to Admin → Add-ons and activate “Billing & Invoicing”.
Step 3: Run Migrations
Step 4: Set Permissions
Assign billing permissions to admin roles under Admin → Users → Roles & Permissions.
Step 5: Configure
Go to Admin → Billing → Settings to configure company details, invoice numbering, tax settings, and notification preferences.
Configuration
All configuration lives in config/billing.php and can be overridden via the admin settings panel (stored in the database via SettingService).
| Key | Default | Description |
|---|---|---|
admin_per_page | 15 | Items per page in admin listings |
invoice_prefix | INV- | Prefix for auto-generated invoice numbers |
invoice_next_number | 1 | Next invoice sequence number |
payment_terms_days | 30 | Default payment terms in days |
credit_note_prefix | CN- | Prefix for credit note numbers |
credit_note_next_number | 1 | Next credit note sequence number |
company_name | — | Your company name (appears on invoices) |
company_address | — | Company address for invoices |
company_phone | — | Company phone number |
company_email | — | Company email address |
company_tax_number | — | Tax/VAT number shown on invoices |
tax_enabled | true | Enable tax calculations |
default_tax_rate_id | null | Default tax rate to apply to new items |
recurring_enabled | true | Enable recurring invoices feature |
recurring_auto_send | false | Auto-send generated recurring invoices |
expenses_enabled | true | Enable expense tracking feature |
expenses_require_approval | false | Require approval for new expenses |
pdf_logo | — | Path to logo image for PDF documents |
pdf_footer_text | — | Custom footer text on PDF documents |
Notification Settings
| Key | Default | Description |
|---|---|---|
notify_invoice_sent | true | Notify customer when invoice is sent |
notify_payment_received | true | Notify customer when payment recorded |
notify_invoice_overdue | true | Notify customer when invoice becomes overdue |
notify_recurring_generated | true | Notify admin when recurring invoice generates |
notify_credit_note_issued | true | Notify customer when credit note issued |
Quote Settings
| Key | Default | Description |
|---|---|---|
quote_validity_days | 30 | Default validity period for quotes |
quote_per_page | 12 | Items per page on front-end quote listing |
quote_admin_per_page | 15 | Items per page in admin quote listings |
allowed_attachment_types | pdf, doc, docx, xls, xlsx, jpg, jpeg, png | Allowed file types for quote request attachments |
max_attachment_size | 10240 | Max attachment size in KB |
notify_new_quote_request | true | Notify admin on new quote request |
notify_quote_submission_confirmation | true | Send confirmation to requester |
notify_quote_request_reviewing | true | Notify requester when status changes to reviewing |
notify_quote_sent | true | Notify requester when quote is sent |
notify_quote_request_accepted | true | Notify requester when request accepted |
notify_quote_request_rejected | true | Notify requester when request rejected |
Admin: Dashboard
The billing dashboard (/admin/billing) provides an at-a-glance overview of your financial status.
Summary Cards
- Total Revenue: sum of all paid invoices
- Outstanding: total balance due across unpaid invoices
- Overdue: total from invoices past due date
- Total Expenses: sum of all approved expenses
- Invoice Count: total invoices created
- Customer Count: total customers
- Payments This Month: payment total for the current month
Revenue Chart
A 12-month bar chart showing monthly revenue trends.
Activity Panels
- Recent Invoices: latest invoices with status badges
- Recent Payments: latest payment entries
- Overdue Invoices: invoices past their due date
- Upcoming Recurring: recurring invoices due to generate soon
Admin: Customers
Manage billing customers at /admin/billing/customers. Customers can optionally be linked to a Larapen user account.
Customer Fields
| Field | Required | Description |
|---|---|---|
company_name | No | Company or organization name |
contact_name | Yes | Primary contact person |
contact_email | Yes | Email for invoice delivery |
contact_phone | No | Phone number |
tax_number | No | Tax/VAT number |
website | No | Customer website URL |
billing_address | No | JSON object with address fields |
shipping_address | No | JSON object with address fields |
default_currency | Yes | Default currency code (e.g. USD) |
payment_terms_days | Yes | Payment terms (default: 30 days) |
notes | No | Internal notes about this customer |
Customer Detail
The customer detail page (/admin/billing/customers/{id}) shows:
- Customer information and contact details
- Statistics: total invoiced, total paid, outstanding balance
- List of all invoices for this customer
Admin: Products
The product catalog (/admin/billing/products) stores reusable line items for invoices. Products are managed via modal dialogs (no separate create/edit pages).
| Field | Required | Description |
|---|---|---|
name | Yes | Product name (translatable) |
description | No | Product description (translatable) |
sku | No | Stock Keeping Unit (unique) |
type | Yes | product or service |
unit_price | Yes | Default unit price |
unit | No | Unit of measure (hrs, pcs, kg, etc.) |
currency | Yes | Currency code |
tax_rate_id | No | Default tax rate for this product |
Available unit options: Unit, Pcs, Hrs, Days, Months, Kg, G, L, ML, M, Km, Box, Pack, Set, Service, Lot.
Admin: Tax Rates
Configure tax rates at /admin/billing/tax-rates. Tax rates are managed via modal dialogs.
| Field | Required | Description |
|---|---|---|
name | Yes | Tax rate name (translatable), e.g. “VAT 20%” |
rate | Yes | Percentage rate (decimal, e.g. 20.0000) |
is_compound | No | Whether this tax compounds on other taxes |
is_default | No | Set as the default tax rate for new items |
Admin: Invoices
The invoice management center at /admin/billing/invoices. Invoices can be filtered by customer, status, and searched by number or content.
Creating an Invoice
Navigate to Billing → Invoices → Create. The invoice form includes:
- Customer: select from existing customers
- Currency: defaults to customer’s currency
- Issue date and Due date: due date auto-calculated from payment terms
- Line items: add from product catalog or enter custom items. Each item has: description (translatable), quantity, unit, unit price, tax rate
- Discount: optional percentage or fixed amount discount
- Notes and Terms: translatable text fields
Invoice numbers are auto-generated using the configured prefix and sequence number (e.g. INV-0001).
Invoice Lifecycle
| Status | Description |
|---|---|
draft | Invoice is being prepared. Can be edited freely. |
sent | Invoice has been sent to the customer. No longer editable. |
partial | Partial payment has been received. |
paid | Invoice has been fully paid. |
overdue | Invoice is past its due date and unpaid. |
cancelled | Invoice has been cancelled. |
refunded | Invoice payment has been refunded (via credit note). |
draft status. Once sent, the invoice is locked.
Available Actions
- Send: marks as sent + emails the customer with a public link
- Update Status: manually change the invoice status
- Duplicate: creates a copy as a new draft invoice
- Download PDF: generates and streams a PDF
- From Quote: convert an accepted quote into an invoice (creates customer if needed)
PDF Generation
PDF invoices are generated using InvoicePdfService with DomPDF. The PDF includes:
- Company logo and details (from settings)
- Customer billing information
- Line items table with quantities, prices, tax, and totals
- Subtotal, tax, discount, and grand total
- Notes and terms
- Custom footer text
Admin: Payments
Record payments at /admin/billing/payments. Payments are linked to invoices and automatically update the invoice balance.
| Field | Required | Description |
|---|---|---|
invoice_id | Yes | The invoice this payment applies to |
amount | Yes | Payment amount |
currency | Yes | Payment currency |
payment_method | Yes | Cash, Bank Transfer, Check, Credit Card, PayPal, Stripe, or Other |
reference | No | Transaction reference number |
payment_date | Yes | Date the payment was received |
notes | No | Internal notes |
When a payment is recorded, the invoice’s amount_paid and balance_due are recalculated. If the balance reaches zero, the invoice is automatically marked as paid.
Admin: Credit Notes
Manage credit notes at /admin/billing/credit-notes. Credit notes are linked to an existing invoice and customer.
Credit Note Lifecycle
| Status | Description |
|---|---|
draft | Credit note is being prepared. |
issued | Credit note has been issued to the customer. |
applied | Credit has been applied to reduce the customer’s balance. |
void | Credit note has been voided. |
Each credit note has its own line items (description, quantity, unit price, tax rate) and an auto-generated number using the configured prefix (e.g. CN-0001).
PDF generation is available for credit notes using the same InvoicePdfService.
Admin: Recurring Invoices
Set up recurring billing at /admin/billing/recurring-invoices.
Recurring Invoice Fields
| Field | Required | Description |
|---|---|---|
customer_id | Yes | Customer to bill |
title | Yes | Template title |
frequency | Yes | Weekly, Monthly, Quarterly, Semi-Annual, or Annual |
interval | Yes | Multiplier (e.g. 2 = every 2 months) |
start_date | Yes | When recurring starts |
next_invoice_date | Yes | Next generation date |
end_date | No | When to stop (null = unlimited) |
occurrences_limit | No | Max invoices to generate (null = unlimited) |
auto_send | No | Auto-send generated invoices |
items | Yes | Line items stored as JSON |
How It Works
- A scheduled command runs daily at 06:00 and checks for recurring invoices where
next_invoice_date ≤ today. - For each due recurring invoice, a new
BillingInvoiceis created from the template items. - The
next_invoice_dateis advanced based on the frequency and interval. - If
auto_sendis enabled, the invoice is immediately marked as sent and the customer is notified. - Generation stops when
end_dateis reached oroccurrences_limitis met.
You can also manually trigger generation via the Generate Now button on a recurring invoice’s detail page.
Admin: Expenses
Track business expenses at /admin/billing/expenses. Expenses are managed via modal dialogs.
| Field | Required | Description |
|---|---|---|
category_id | No | Expense category |
vendor | No | Vendor or supplier name |
reference | No | Reference/receipt number |
amount | Yes | Expense amount |
currency | Yes | Currency code |
expense_date | Yes | Date of expense |
notes | No | Description or notes |
receipt | No | Receipt file upload |
Expense Statuses
| Status | Description |
|---|---|
pending | Awaiting approval (when approval is required) |
approved | Expense has been approved |
rejected | Expense has been rejected |
expenses_require_approval is enabled in settings, new expenses start as pending. An admin with billing.expenses.edit permission can approve or reject them.
Expense Categories
Organize expenses by category at /admin/billing/expense-categories. Categories have a translatable name and description, and can be activated/deactivated.
Admin: Quote System
The quote system handles the full lifecycle from customer request to accepted proposal to invoice.
Quote Requests
View and manage incoming quote requests at /admin/billing/quotes/requests.
Request Fields
| Field | Description |
|---|---|
reference_number | Auto-generated unique reference (e.g. QR-0001) |
category_id | Optional category (from the unified categories table) |
company_name | Requester’s company |
contact_name | Requester’s name |
contact_email | Requester’s email |
title | Project title (translatable) |
description | Project description (translatable) |
requirements | Detailed requirements (translatable) |
budget_min / budget_max | Budget range |
timeline | Expected timeline |
priority | Low, Normal, High, or Urgent |
attachment | Optional file attachment |
Request Statuses
| Status | Description |
|---|---|
pending | New request awaiting review |
reviewing | Request is being reviewed |
quoted | A quote has been sent |
accepted | Request/quote accepted by requester |
rejected | Request declined |
cancelled | Request cancelled |
Quote Proposals
Create proposals at /admin/billing/quotes/quotes. Each quote is linked to a quote request.
Quote Fields
| Field | Description |
|---|---|
quote_number | Auto-generated unique number |
request_id | Linked quote request |
title | Quote title (translatable) |
scope | Scope of work (translatable) |
terms | Terms and conditions (translatable) |
items | Line items with description, quantity, unit, unit price |
amount | Total quote amount |
currency | Currency code |
valid_until | Quote expiration date |
Quote Statuses
| Status | Description |
|---|---|
draft | Quote is being prepared |
sent | Quote sent to requester with public link |
accepted | Quote accepted: can be converted to invoice |
rejected | Quote rejected by requester |
expired | Quote validity period has passed |
Quote Categories
Manage quote categories at /admin/billing/quotes/categories. These are standard category entries from the unified categories table, scoped to quote requests. Categories appear on the public quote request form.
Admin: Settings
All billing settings are managed at /admin/billing/settings. The settings form is grouped into sections:
- Company Information: name, address, phone, email, tax number
- Invoice Settings: prefix, next number, payment terms
- Credit Note Settings: prefix, next number
- Tax Settings: enable/disable, default tax rate
- Recurring Settings: enable/disable, auto-send
- Expense Settings: enable/disable, require approval
- Quote Settings: validity days, attachments, per-page
- PDF Settings: logo, footer text
- Notifications: toggle each notification type on/off
Settings are stored in the database via the SettingService (prefixed with billing_) and cached for performance.
Front-end: Quote Request Form
URL & Routes
| Route | URL | Description |
|---|---|---|
front.billing.quotes.index | /quote-requests/new | Display quote request form |
front.billing.quotes.submit | POST /quote-requests/submit | Submit quote request |
Localized variants are also registered (e.g. /fr/quote-requests/new).
Form Fields
Visitors can fill out the following fields:
- Contact info: name, email, phone, company name
- Category: select from configured quote categories
- Project details: title, description, requirements (translatable)
- Budget: minimum and maximum range with currency
- Timeline: expected project timeline
- Priority: Low, Normal, High, or Urgent
- Attachment: optional file upload (validated against allowed types and max size)
After Submission
- A
BillingQuoteRequestrecord is created with a unique reference number. - The admin receives a
NewQuoteRequestNotification(if enabled). - The requester receives a
QuoteSubmissionConfirmationNotification(if enabled). - The visitor’s IP address is recorded.
front_menu entry in addon.json with the label “Get a Quote” and route front.billing.quotes.index. This can be added to any navigation menu.
Front-end: Public Invoice View
URL & Routes
| Route | URL | Description |
|---|---|---|
front.billing.invoice.show | /billing/invoice/{token} | View invoice (public, no auth required) |
front.billing.invoice.pdf | /billing/invoice/{token}/pdf | Download PDF |
Each invoice has a unique 64-character public_token generated on creation. This token is included in the email sent to the customer, allowing them to view and download the invoice without logging in.
The public view displays: company details, customer details, line items, totals, payment status, and notes/terms.
Front-end: Public Quote View
URL & Routes
| Route | URL | Description |
|---|---|---|
front.billing.quote.show | /billing/quote/{token} | View quote (public, no auth required) |
front.billing.quote.pdf | /billing/quote/{token}/pdf | Download PDF |
Quotes also have a unique public_token. The public view shows: scope of work, line items, total amount, validity period, and terms.
Front-end: Online Payment
URL & Routes
| Route | URL | Description |
|---|---|---|
front.billing.invoice.checkout | /billing/invoice/{token}/pay | Payment checkout page |
front.billing.invoice.pay | POST /billing/invoice/{token}/pay | Process payment |
The BillingInvoice model implements the Payable contract, making it compatible with any payment gateway add-on (Stripe, PayPal, etc.). The contract provides:
getPayableAmount(): returns the balance duegetPayableDescription(): invoice number and descriptiongetPayableCurrency(): invoice currencygetPayableCustomerEmail(): customer emailgetPayableCustomerName(): customer display namegetPayableUserId(): linked user ID (if any)getPayableIdentifier(): unique identifier for the paymentgetPaymentSuccessUrl(): redirect URL after successful paymentgetPaymentCancelUrl(): redirect URL after cancelled payment
When payment succeeds, the invoice’s markAsPaid() method is called. On failure, markPaymentFailed() is called.
Notifications
The add-on includes 11 notification classes, all in Addons\Billing\Notifications:
Invoice & Payment Notifications
| Notification | Recipient | Trigger |
|---|---|---|
InvoiceSentNotification | Customer | Invoice marked as sent |
PaymentReceivedNotification | Customer / Admin | Payment recorded |
InvoiceOverdueNotification | Customer | Invoice becomes overdue (via scheduled command) |
RecurringInvoiceGeneratedNotification | Admin | Recurring invoice generates a new invoice |
CreditNoteIssuedNotification | Customer | Credit note issued |
Quote Notifications
| Notification | Recipient | Trigger |
|---|---|---|
NewQuoteRequestNotification | Admin | New quote request submitted |
QuoteSubmissionConfirmationNotification | Requester | After form submission |
QuoteRequestReviewingNotification | Requester | Status changed to “reviewing” |
QuoteSentNotification | Requester | Quote sent with public link |
QuoteRequestAcceptedNotification | Requester | Request accepted |
QuoteRequestRejectedNotification | Requester | Request rejected |
Each notification can be individually toggled on/off in Billing → Settings.
Updating
Step 1: Replace Files
Replace the billing folder in extensions/addons/ with the new version.
Step 2: Run Migrations
Step 3: Clear Caches
Step 4: Verify
- Check that all billing pages load correctly in the admin panel.
- Verify the dashboard statistics are accurate.
- Test creating a new invoice and generating a PDF.
- Check that scheduled commands still run correctly.
Troubleshooting
Invoice PDF fails to generate
- Ensure
barryvdh/laravel-dompdfis installed:composer require barryvdh/laravel-dompdf. - Check that the PDF logo path (in settings) points to a valid image file.
- Verify the
storagedirectory is writable.
Recurring invoices not generating
- Ensure the Laravel scheduler is running:
* * * * * cd /path-to-project && php artisan schedule:run >> /dev/null 2>&1 - Check that the recurring invoice is active (
is_active = true). - Verify
next_invoice_dateis not in the future. - Check
end_dateandoccurrences_limithaven’t been reached. - Run manually to debug:
php artisan billing:generate-recurring
Overdue notifications not sent
- Check that
notify_invoice_overdueis enabled in billing settings. - Verify the invoice status is
sentorpartial(only these statuses transition to overdue). - Check mail configuration in
.env(SMTP settings). - Run manually to debug:
php artisan billing:check-overdue
Online payment not available
- At least one payment gateway add-on (Stripe, PayPal, etc.) must be installed and active.
- The invoice must implement the
Payablecontract (built-in). - The invoice must have a
balance_due > 0and a validpublic_token.
Quote request form not visible
- Ensure the billing add-on is activated.
- Check that the route
front.billing.quotes.indexis accessible. - If using a menu link, verify the menu item points to the correct route.
Customer not linked to user account
- The
user_idfield on billing customers is optional. - When converting a quote to an invoice, a new billing customer is created automatically if one doesn’t exist for the requester.
- You can manually link a customer to a user via the customer edit form.
Tax calculations seem incorrect
- Tax is calculated per line item, not on the invoice total.
- Verify the correct tax rate is assigned to each line item.
- Check if compound tax rates are being used correctly: compound taxes apply on top of other taxes.
- Ensure
tax_enabledis set totruein billing settings.