Download the PHP package salehye/invoicing without Composer
On this page you can find all versions of the php package salehye/invoicing. It is possible to download/install these versions without Composer. Possible dependencies are resolved automatically.
Download salehye/invoicing
More information about salehye/invoicing
Files in salehye/invoicing
Package invoicing
Short Description A standalone Laravel invoicing library with multi-gateway payment support, bank transfer verification, and Overdue status tracking
License MIT
Homepage https://github.com/salehye/invoicing
Informations about the package invoicing
salehye/invoicing
A standalone Laravel invoicing package with multi-gateway payment support โ create invoices, manage line items with taxes/discounts, and process payments through Stripe, bank transfer (with manual admin verification), local testing, or any custom gateway.
Zero dependency on subscription billing packages โ use independently or alongside any subscription system.
โจ Features
- ๐งพ Invoice creation for any billable entity (polymorphic) or standalone (no billable required)
- ๐ฆ Line items with quantity, pricing, per-line discount & tax
- ๐ฐ Percentage & fixed discounts via
DiscountTypebacked enum - ๐ Configurable tax calculation (VAT, sales tax, etc.)
- ๐ข Unique invoice number generation with collision-safe retry
- ๐ Status lifecycle:
draft โ unpaid โ paid โ refunded/canceled/overdue - โฐ Overdue detection +
invoicing:mark-overdueartisan command - ๐ณ Multi-gateway payments (Stripe, Local, Bank Transfer with manual verification)
- ๐ Payment amount validation (no negative or excessive amounts)
- โ Automatic invoice marking as paid when fully paid
- ๐ก Laravel events with
readonlyimmutable properties - ๐ก๏ธ Custom exception hierarchy for domain-specific errors
- ๐ช Middleware to restrict routes by invoice payment status
- ๐
HasInvoicestrait for any Eloquent model - ๐ค User ID tracking on invoices & payments
- ๐ข Tenant ID support (multi-tenant)
- ๐๏ธ Soft deletes on invoices (audit trail)
- ๐
$fillablemass-assignment security - ๐ก๏ธ
restrictOnDeleteon FKs (no cascade deletes โ preserves audit trail) - ๐ Metadata JSON for extra data
- ๐งฉ Customizable table names, currency, and user model
- ๐ฏ Custom tax/discount calculator contracts
๐ฆ Installation
Publish Config & Migrations
Environment Variables
โ๏ธ Configuration
Full config file at config/invoicing.php:
| Key | Default | Description |
|---|---|---|
currency |
USD |
Default currency per invoice |
invoice_number_format |
{prefix}-{year}-{sequence} |
Invoice number template |
invoice_number_prefix |
INV |
Invoice number prefix |
invoice_number_sequence_length |
4 |
Sequence digit count |
default_gateway |
local |
Default payment gateway |
gateways.* |
โ | Per-gateway config (see Gateways section) |
default_tax_rate |
0 |
Default tax % (0 = no tax) |
overdue_threshold_days |
0 |
Days past due_at before overdue |
table_names.invoices |
invoices |
Invoices table name |
table_names.invoice_lines |
invoice_lines |
Invoice lines table name |
table_names.payments |
payments |
Payments table name |
user_model |
App\Models\User |
User model for relationships |
๐ Quick Start
Step 1: Make a Model Billable
This adds: invoices(), unpaidInvoices(), paidInvoices(), overdueInvoices(), totalInvoiceBalance()
Step 2: Create an Invoice
Step 3: Issue the Invoice
Step 4: Process Payment
๐ Invoices
Creating Invoices
Invoice with Discount & Tax
โ ๏ธ
discount_typeis required whendiscount > 0. No silent default โ the package throws an error if you provide a discount without specifying its type.
Invoice with Metadata
Line Items with Per-Line Tax & Discount
Adding Lines After Creation
Invoice Number Format
Customize in config:
Available placeholders: {prefix}, {year}, {month}, {sequence}
Examples: INV-2025-0001, INV-2025-06-0001
The generator automatically handles collisions with a bounded retry loop (max 10 attempts).
๐ Invoice Lifecycle
Status Transitions
Operations
Invalid transitions throw InvoiceStatusTransitionException.
Overdue Status
Configure grace period:
Schedule the command in routes/console.php (Laravel 11+) or Console/Kernel.php:
Status Helpers
Financial Helpers
Query Scopes
๐ณ Payments
Record a Manual Payment
Mark Payment as Success/Failed
Create Checkout Session
Handle Webhooks
Refund
Payment Helpers
๐ฆ Payment Gateways
Built-in Gateways
| Gateway | Status | Description |
|---|---|---|
| LocalGateway | โ Ready | Auto-succeeds for local/testing |
| StripeGateway | ๐ Placeholder | Requires stripe/stripe-php |
| BankTransferGateway | โ Ready | Manual admin verification |
โ ๏ธ Stripe: throws
RuntimeExceptionifstripe/stripe-phpis not installed. Install withcomposer require stripe/stripe-php.
Switch Default Gateway
Or via env: INVOICING_GATEWAY=stripe
Use a Specific Gateway per Payment
Add Custom Gateway โ Via Config
Add Custom Gateway โ Via Runtime
Custom Gateway Implementation
Gateway Manager API
๐ฆ Bank Transfer (Manual Verification)
Flow
1. Customer Initiates
2. Admin Verifies or Rejects
3. Bank Details Config
Payment Status Flow
PaymentStatus Transitions
Invalid transitions throw PaymentStatusTransitionException.
๐ก๏ธ Exceptions
| Exception | Thrown When |
|---|---|
InvoiceStatusTransitionException |
Invalid invoice status transition |
PaymentStatusTransitionException |
Invalid payment status transition |
PaymentVerificationException |
verify/reject on non-awaiting_verification payment |
GatewayNotFoundException |
Unregistered gateway requested |
InvalidPaymentAmountException |
Amount โค 0 or exceeds remaining balance |
All extend standard PHP exceptions (RuntimeException / InvalidArgumentException) so they integrate naturally with Laravel's error handling.
๐ก Events
All events use public readonly properties (immutable after construction):
| Event | Property | When |
|---|---|---|
InvoiceCreated |
$invoice |
Invoice created |
InvoiceUpdated |
$invoice |
Issued / totals recalculated |
InvoicePaid |
$invoice |
Marked as paid |
InvoiceCanceled |
$invoice |
Canceled |
InvoiceRefunded |
$invoice |
Refunded |
PaymentSucceeded |
$payment |
Payment succeeded |
PaymentFailed |
$payment |
Payment failed |
PaymentVerified |
$payment |
Admin verified bank transfer |
Listening
Example Listener
๐ช Middleware
EnsureInvoicePaid
The invoice.paid middleware alias is auto-registered by the package's ServiceProvider (works in Laravel 11, 12, and 13). No manual registration needed.
Restrict route access by invoice payment status:
If you prefer manual registration, you can also add it in bootstrap/app.php:
Note: The auto-registration is preferred and works out of the box. Manual registration is only needed if you want to override the alias or have a conflicting alias name.
๐ HasInvoices Trait
All methods return MorphMany with proper return type declarations.
๐ค User ID Tracking
Track who created/owns invoices and payments (independent from billable):
Custom User Model
๐งฎ Custom Calculators
Tax Calculator
Discount Calculator
๐๏ธ Database Schema
invoices
| Column | Type | Notes |
|---|---|---|
id |
bigint | PK |
billable_type |
string | Polymorphic (nullable) |
billable_id |
bigint | Polymorphic (nullable) |
user_id |
bigint | Nullable, indexed (app adds FK) |
tenant_id |
string | Nullable, indexed |
number |
string | Unique |
title |
string | Required |
description |
text | Nullable |
currency |
string(3) | Default: USD |
subtotal |
decimal(12,2) | Sum of line totals |
discount |
decimal(12,2) | Discount amount |
discount_type |
enum | percentage / fixed (DiscountType cast) |
tax |
decimal(12,2) | Tax amount |
total |
decimal(12,2) | Final total |
status |
enum | draft/unpaid/paid/canceled/refunded/overdue |
issued_at |
timestamp | Nullable |
due_at |
timestamp | Nullable |
paid_at |
timestamp | Nullable |
metadata |
json | Nullable |
created_at |
timestamp | |
updated_at |
timestamp | |
deleted_at |
timestamp | Soft delete |
invoice_lines
| Column | Type | Notes |
|---|---|---|
id |
bigint | PK |
invoice_id |
bigint | FKโinvoices (restrictOnDelete) |
description |
string | Required |
quantity |
integer | Default: 1 |
unit_price |
decimal(12,2) | |
discount |
decimal(12,2) | Per-line discount |
tax |
decimal(12,2) | Per-line tax |
total |
decimal(12,2) | (unit_price ร qty) โ discount + tax |
metadata |
json | Nullable |
payments
| Column | Type | Notes |
|---|---|---|
id |
bigint | PK |
invoice_id |
bigint | FKโinvoices (restrictOnDelete) |
user_id |
bigint | Nullable, indexed (app adds FK) |
gateway |
string | e.g. manual, stripe, bank_transfer |
transaction_id |
string | Nullable |
amount |
decimal(12,2) | Must be > 0 and โค remaining balance |
currency |
string(3) | |
status |
enum | pending/awaiting_verification/success/failed/refunded |
gateway_response |
json | Nullable |
proof_file |
string | Nullable โ bank transfer receipt |
proof_notes |
string | Nullable โ customer/admin notes |
verified_at |
timestamp | Nullable โ admin verification time |
verified_by |
bigint | Nullable, indexed โ admin user ID (app adds FK) |
created_at |
timestamp | |
updated_at |
timestamp |
FK Constraints:
user_idandverified_byareforeignId(unsignedBigInteger) columns with indexes but withoutconstrained()because the target user table is configurable. The consuming application should add FK constraints in their own migrations.invoice_idusesrestrictOnDeleteto preserve the financial audit trail.
๐งช Testing
56 tests, 121 assertions covering:
- โ Invoice creation with items & totals
- โ Percentage & fixed discount + tax calculations
- โ DiscountType enum casting
- โ Unique invoice number generation
- โ Status lifecycle (draft โ unpaid โ paid โ refunded โ canceled โ overdue)
- โ Invalid transitions โ InvoiceStatusTransitionException
- โ Polymorphic billable relationships
- โ Standalone invoices (no billable)
- โ Line items
- โ Overdue detection
- โ Gateway registration & resolution
- โ Custom gateway runtime registration
- โ GatewayNotFoundException
- โ Bank transfer: initiate, verify, reject
- โ PaymentVerificationException
- โ InvalidPaymentAmountException
- โ User ID on invoices and payments
- โ HasInvoices trait
- โ discount_type validation (required when discount > 0)
- โ PaymentStatus::canTransitionTo() transitions
- โ PaymentStatusTransitionException on invalid transitions
- โ Invoice::isFullyPaid(), hasLines(), lineCount()
- โ Invoice scopes: forTenant(), forUser(), status()
- โ HasInvoices: draftInvoices(), canceledInvoices(), refundedinvoices(), totalPaidAmount()
- โ Overdue scope includes unpaid past due_at (not just Overdue status)
๐ Documentation
- API Reference โ Complete method signatures
- Usage Examples โ Real-world scenarios
๐ Changelog
See CHANGELOG.md for all changes.
๐ License
MIT โ free to use in personal and commercial projects.
๐ค Contributing
- Fork the repository
- Create a feature branch (
git checkout -b feature/my-feature) - Commit your changes (
git commit -am 'Add my feature') - Push to the branch (
git push origin feature/my-feature) - Create a Pull Request
Please ensure all tests pass before submitting: