aldiazhar/laravel-invoice
Composer 安装命令:
composer require aldiazhar/laravel-invoice
包简介
A flexible and powerful invoice management package for Laravel
README 文档
README
A flexible and powerful invoice management package for Laravel applications.
Requirements
- PHP 8.1, 8.2, or 8.3
- Laravel 10.x, 11.x, or 12.x
Installation
composer require aldiazhar/laravel-invoice
Publish Assets
php artisan vendor:publish --tag=invoice-config php artisan vendor:publish --tag=invoice-migrations php artisan migrate
Quick Start Guide
Two Ways to Create Invoice
Method 1: From Payer (User) Perspective
$invoice = $user->invoice() ->pay($payment) // What to pay ->create();
Method 2: From Invoiceable (Payment) Perspective
$invoice = $payment->bill() ->to($user) // Bill to whom ->create();
Both methods create the same invoice!
1. Setup Models
User Model (Payer):
use Aldiazhar\Invoice\Contracts\Payer; use Aldiazhar\Invoice\Traits\HasInvoices; class User extends Model implements Payer { use HasInvoices; public function getPayerName(): string { return $this->name; } public function getPayerEmail(): ?string { return $this->email; } public function getPayerAddress(): ?string { return $this->address; } public function getPayerMetadata(): array { return ['phone' => $this->phone]; } }
Payment Model (Invoiceable):
use Aldiazhar\Invoice\Contracts\Invoiceable; use Aldiazhar\Invoice\Traits\Invoiceable as InvoiceableTrait; class Payment extends Model implements Invoiceable { use InvoiceableTrait; public function getInvoiceableDescription(): string { return "Payment #{$this->id}"; } public function getInvoiceableAmount(): float { return $this->amount; } public function getInvoiceableMetadata(): array { return [ 'payment_method' => $this->payment_method, 'reference' => $this->reference_number, ]; } public function onInvoicePaid($invoice): void { $this->update(['status' => 'completed']); } }
2. Create Invoice
Auto Item (Recommended - No items needed!):
// From Payer perspective $invoice = $user->invoice() ->pay($payment) ->create(); // From Invoiceable perspective $invoice = $payment->bill() ->to($user) ->create();
Item otomatis dibuat dari getInvoiceableDescription() dan getInvoiceableAmount()
Manual Single Item:
$invoice = $user->invoice() ->pay($payment) ->item('Payment Processing', 100000) ->create();
Multiple Items:
$invoice = $user->invoice() ->pay($order) ->item('Product A', 50000, 2) ->item('Product B', 75000, 1) ->tax(10000) ->discount(5000) ->create();
Using Array:
$invoice = $user->invoice() ->pay($order) ->items([ ['name' => 'Product A', 'price' => 50000, 'quantity' => 2, 'tax_rate' => 0.11], ['name' => 'Product B', 'price' => 75000, 'quantity' => 1], ]) ->create();
Without Auto Item (Manual Control):
$invoice = $user->invoice() ->pay($order) ->withoutAutoItem() ->item('Custom Item', 100000) ->create();
Advanced:
$invoice = $user->invoice() ->pay($order) ->item('Premium Package', 500000) ->tax(20000) ->discount(50000) ->currency('USD') ->due('2024-12-31') ->description('Monthly subscription') ->meta(['campaign_id' => 123]) ->after(function($invoice) { // Custom logic after create }) ->onPaid(function($invoice) { // Custom logic when paid }) ->create();
3. Invoice Management
$invoice->markAsPaid(); $invoice->cancel(); $invoice->markAsFailed(); $invoice->refund(); if ($invoice->isPaid()) { // } if ($invoice->isOverdue()) { // }
4. Partial Payments
$invoice->addPayment(50000, 'bank_transfer', [ 'reference' => 'TRX-123', 'notes' => 'First installment', ]); $paidAmount = $invoice->getPaidAmount(); $remaining = $invoice->getRemainingAmount(); $isFullyPaid = $invoice->isFullyPaid();
5. Recurring Invoices
$invoice = $user->invoice() ->pay($subscription) ->item('Monthly Premium', 99000) ->makeRecurring('monthly', now()->addYear()) ->create(); $schedule->command('invoices:generate-recurring')->daily();
6. Query & Statistics
use Aldiazhar\Invoice\Facades\Invoice; $pending = Invoice::pending(); $paid = Invoice::paid(); $overdue = Invoice::overdue(); $stats = Invoice::stats(); $userStats = $user->getInvoiceStats();
7. Activity Log
$activities = $invoice->activities; foreach ($activities as $activity) { echo $activity->action; echo $activity->description; echo $activity->causer->name; }
Auto Item Feature
Default Behavior (Auto Item Enabled):
$payment = Payment::create(['amount' => 100000]); $invoice = $user->invoice() ->pay($payment) ->create();
Secara otomatis membuat item dengan:
- Name: dari
getInvoiceableDescription() - Price: dari
getInvoiceableAmount() - Quantity: 1
Disable Auto Item:
$invoice = $user->invoice() ->pay($payment) ->withoutAutoItem() ->item('Custom Item', 50000) ->item('Another Item', 50000) ->create();
Force Add Invoiceable Item:
$invoice = $user->invoice() ->pay($payment) ->item('Extra Service', 20000) ->withInvoiceableItem() ->create();
Total: 120000 (100000 from payment + 20000 from extra)
Configuration
Edit config/invoice.php:
return [ 'currency' => 'USD', 'due_date_days' => 30, 'strict_validation' => true, 'invoice_number' => [ 'prefix' => 'INV-', 'format' => 'Ymd', 'padding' => 4, ], ];
Validation
Strict Mode (Default)
Invoice total must match invoiceable amount:
$payment = Payment::create(['amount' => 100000]); $invoice = $user->invoice() ->pay($payment) ->create();
Total: 100000
$invoice = $user->invoice() ->pay($payment) ->item('Custom', 50000) ->create();
Error: Mismatch! Expected 100000, got 50000
Disable Strict Mode
$invoice = $user->invoice() ->pay($payment) ->item('Custom', 50000) ->withoutStrictValidation() ->create();
Total: 50000
API Reference
InvoiceBuilder Methods
// Set who pays ->to($payer) // Set payer (who will pay) // Set what to pay ->pay($invoiceable) // Set invoiceable (what to pay) // Items ->item($name, $price, $quantity = 1, $taxRate = 0) ->items(array $items) ->withInvoiceableItem() ->withoutAutoItem() // Amounts ->tax(float $amount) ->discount(float $amount) // Details ->currency(string $currency) ->status(string $status) ->due($date) ->description(string $description) ->meta(array $metadata) // Options ->withoutStrictValidation() ->makeRecurring($frequency, $endDate, $interval) // Callbacks ->after(callable $callback) ->onPaid(callable $callback) // Execute ->create()
Invoice Methods
$invoice->markAsPaid() $invoice->cancel() $invoice->markAsFailed() $invoice->refund() $invoice->addPayment($amount, $method, $data) $invoice->generateNextInvoice() $invoice->isPaid() $invoice->isPending() $invoice->isOverdue() $invoice->getPaidAmount() $invoice->getRemainingAmount() $invoice->isFullyPaid()
Query Scopes
Invoice::pending() Invoice::paid() Invoice::failed() Invoice::overdue() Invoice::forPayer($payer) Invoice::forInvoiceable($invoiceable)
Examples
Simple Payment Invoice (Auto Item)
$payment = Payment::create([ 'user_id' => $user->id, 'amount' => 150000, 'payment_method' => 'bank_transfer', ]); $invoice = $user->invoice() ->pay($payment) ->create();
Item dibuat otomatis dari payment!
E-Commerce Order (Manual Items)
$invoice = $user->invoice() ->pay($order) ->withoutAutoItem() ->items($order->items->map(fn($item) => [ 'name' => $item->product->name, 'price' => $item->price, 'quantity' => $item->quantity, 'sku' => $item->product->sku, ])->toArray()) ->tax($order->tax_amount) ->discount($order->discount_amount) ->create();
Subscription (Recurring + Auto Item)
$subscription = Subscription::create([ 'plan' => 'premium', 'price' => 99000, ]); $invoice = $user->invoice() ->pay($subscription) ->makeRecurring('monthly') ->onPaid(function($invoice) { $invoice->invoiceable->renew(); }) ->create();
Service Payment (Mixed Items)
$service = Service::create([ 'name' => 'Consulting', 'base_amount' => 1200, ]); $invoice = $user->invoice() ->pay($service) ->withInvoiceableItem() ->item('Travel Cost', 200) ->item('Materials', 100) ->tax(0.11) ->create();
Total: 1500 + 11% tax
Troubleshooting
Interface Implementation Issue
Jika muncul error "must implement Invoiceable interface", pastikan:
use Aldiazhar\Invoice\Contracts\Invoiceable; use Aldiazhar\Invoice\Traits\InvoiceableTrait; class Payment extends Model implements Invoiceable { use InvoiceableTrait; public function getInvoiceableDescription(): string { return "Payment #{$this->id}"; } public function getInvoiceableAmount(): float { return $this->amount; } }
Jangan lupa implement semua method yang required!
Using bill()->to() vs invoice()->pay()
// These are EQUIVALENT: // Option 1: From Payer $user->invoice()->pay($payment)->create(); // Option 2: From Invoiceable $payment->bill()->to($user)->create(); // Both create the same invoice!
Amount Mismatch Error
$payment = Payment::create(['amount' => 100000]); $invoice = $user->invoice() ->pay($payment) ->item('Custom', 50000) ->withoutStrictValidation() ->create();
Atau pastikan total items = invoiceable amount
License
MIT License
Support
- GitHub: aldiazhar/laravel-invoice
- Issues: GitHub Issues
统计信息
- 总下载量: 14
- 月度下载量: 0
- 日度下载量: 0
- 收藏数: 0
- 点击次数: 0
- 依赖项目数: 0
- 推荐数: 0
其他信息
- 授权协议: MIT
- 更新时间: 2025-11-15