PHPackages                             finller/laravel-invoices - PHPackages - PHPackages  [Skip to content](#main-content)[PHPackages](/)[Directory](/)[Categories](/categories)[Trending](/trending)[Leaderboard](/leaderboard)[Changelog](/changelog)[Analyze](/analyze)[Collections](/collections)[Log in](/login)[Sign up](/register)

1. [Directory](/)
2. /
3. [PDF &amp; Document Generation](/categories/documents)
4. /
5. finller/laravel-invoices

Abandoned → [elegantly/laravel-invoices](/?search=elegantly%2Flaravel-invoices)Library[PDF &amp; Document Generation](/categories/documents)

finller/laravel-invoices
========================

Store invoices safely in your Laravel application

v4.7.2(2mo ago)23111.9k↓89.6%24[2 PRs](https://github.com/ElegantEngineeringTech/laravel-invoices/pulls)MITPHPPHP ^8.1CI passing

Since Dec 15Pushed 1mo ago3 watchersCompare

[ Source](https://github.com/ElegantEngineeringTech/laravel-invoices)[ Packagist](https://packagist.org/packages/finller/laravel-invoices)[ Docs](https://github.com/ElegantEngineeringTech/laravel-invoices)[ RSS](/packages/finller-laravel-invoices/feed)WikiDiscussions main Synced 1mo ago

READMEChangelog (10)Dependencies (14)Versions (95)Used By (0)

Everything You Need to Manage Invoices in Laravel
=================================================

[](#everything-you-need-to-manage-invoices-in-laravel)

[![Latest Version on Packagist](https://camo.githubusercontent.com/93e4c499ef11238b20ed4f231a66e8f79ad5c73d8a67212b297ee06b02061dc0/68747470733a2f2f696d672e736869656c64732e696f2f7061636b61676973742f762f656c6567616e746c792f6c61726176656c2d696e766f696365732e7376673f7374796c653d666c61742d737175617265)](https://packagist.org/packages/elegantly/laravel-invoices)[![GitHub Tests Action Status](https://camo.githubusercontent.com/0a77af6b19e1af0036a096197c30649b3cacca5088763f91f723cf4d9958c3b6/68747470733a2f2f696d672e736869656c64732e696f2f6769746875622f616374696f6e732f776f726b666c6f772f7374617475732f456c6567616e74456e67696e656572696e67546563682f6c61726176656c2d696e766f696365732f72756e2d74657374732e796d6c3f6272616e63683d6d61696e266c6162656c3d7465737473267374796c653d666c61742d737175617265)](https://github.com/ElegantEngineeringTech/laravel-invoices/actions?query=workflow%3Arun-tests+branch%3Amain)[![GitHub Code Style Action Status](https://camo.githubusercontent.com/5858718d6d20168d1b2d540d555beddd97fb55788628c2c99b0500f2a6bd9b61/68747470733a2f2f696d672e736869656c64732e696f2f6769746875622f616374696f6e732f776f726b666c6f772f7374617475732f456c6567616e74456e67696e656572696e67546563682f6c61726176656c2d696e766f696365732f6669782d7068702d636f64652d7374796c652d6973737565732e796d6c3f6272616e63683d6d61696e266c6162656c3d636f64652532307374796c65267374796c653d666c61742d737175617265)](https://github.com/ElegantEngineeringTech/laravel-invoices/actions?query=workflow%3A%22Fix+PHP+code+style+issues%22+branch%3Amain)[![Total Downloads](https://camo.githubusercontent.com/854b187add1a2b3a6babd99ccfd12c9ff88ace3d74e917c52780e9578fee24fe/68747470733a2f2f696d672e736869656c64732e696f2f7061636b61676973742f64742f656c6567616e746c792f6c61726176656c2d696e766f696365732e7376673f7374796c653d666c61742d737175617265)](https://packagist.org/packages/elegantly/laravel-invoices)

This package provides a robust, easy-to-use system for managing invoices within a Laravel application, with options for database storage, serial numbering, and PDF generation.

[![laravel-invoices](https://repository-images.githubusercontent.com/527661364/f98e92f9-62a6-48a1-a7b1-1a587b92a430)](https://repository-images.githubusercontent.com/527661364/f98e92f9-62a6-48a1-a7b1-1a587b92a430)

Interactive Demo
----------------

[](#interactive-demo)

Try out [the interactive demo](https://elegantly.dev/laravel-invoices) to explore package capabilities.

Table of Contents
-----------------

[](#table-of-contents)

- [Requirements](#requirements)
- [Installation](#installation)
- [The `PdfInvoice` Class](#the-pdfinvoice-class)
    - [Full Example](#full-example)
    - [Rendering the Invoice as a PDF](#rendering-the-invoice-as-a-pdf)
    - [Storing the PDF in a file](#storing-the-pdf-in-a-file)
    - [Downloading the Invoice as a PDF](#downloading-the-invoice-as-a-pdf)
        - [From a controller](#from-a-controller)
        - [From a Livewire component](#from-a-livewire-component)
    - [Rendering the Invoice as a view](#rendering-the-invoice-as-a-view)
    - [Rendering the Invoice within a View](#rendering-the-invoice-within-a-view)
    - [Adding Taxes](#adding-taxes)
        - [Tax by Percentage](#tax-by-percentage)
        - [Tax as a Fixed Amount](#tax-as-a-fixed-amount)
    - [Adding Discounts](#adding-discounts)
        - [Discount by Percentage](#discount-by-percentage)
        - [Discount as a Fixed Amount](#discount-as-a-fixed-amount)
    - [Adding Payment Instructions](#adding-payment-instructions)
        - [QR Code Generation](#qr-code-generation)
    - [Customization](#customization)
        - [Customizing Fonts](#customizing-fonts)
        - [Customizing the Invoice Template](#customizing-the-invoice-template)
- [The `Invoice` Eloquent Model](#the-invoice-eloquent-model)
    - [Complete Example](#complete-example)
    - [Generating Unique Serial Numbers](#generating-unique-serial-numbers)
    - [Using Multiple Prefixes and Series for Serial Numbers](#using-multiple-prefixes-and-series-for-serial-numbers)
    - [Customizing the Serial Number Format](#customizing-the-serial-number-format)
    - [Storing the Logo](#storing-the-logo)
    - [Storing a Dynamic Logo](#storing-a-dynamic-logo)
    - [Converting an `Invoice` Model to a `PdfInvoice`](#converting-an-invoice-model-to-a-pdfinvoice)
    - [Display, Download, and Store Invoices](#display-download-and-store-invoices)
    - [Attaching Invoices to Mailables](#attaching-invoices-to-mailables)
    - [Attaching Invoices to Notifications](#attaching-invoices-to-notifications)
    - [Customizing PDF Output from the Model](#customizing-pdf-output-from-the-model)
        - [Using a Custom PdfInvoice Class](#using-a-custom-pdfinvoice-class)
    - [Casting `state` and `type` to Enums](#casting-state-and-type-to-enums)
- [Testing](#testing)
- [Changelog](#changelog)
- [Contributing](#contributing)
- [Security Vulnerabilities](#security-vulnerabilities)
- [Credits](#credits)
- [License](#license)

Requirements
------------

[](#requirements)

- PHP 8.1+
- Laravel 11.0+
- `dompdf/dompdf` for PDF rendering
- `elegantly/laravel-money` for money computation which use `brick\money` under the hood

Installation
------------

[](#installation)

You can install the package via composer:

```
composer require elegantly/laravel-invoices
```

If you intent to store your invoices using the Eloquent Model, you must publish and run the migrations with:

```
php artisan vendor:publish --tag="invoices-migrations"
php artisan migrate
```

You can publish the config file with:

```
php artisan vendor:publish --tag="invoices-config"
```

This is the contents of the published config file:

```
use Brick\Math\RoundingMode;
use Elegantly\Invoices\Enums\InvoiceType;
use Elegantly\Invoices\InvoiceDiscount;
use Elegantly\Invoices\Models\Invoice;
use Elegantly\Invoices\Models\InvoiceItem;

return [

    'model_invoice' => Invoice::class,
    'model_invoice_item' => InvoiceItem::class,

    'discount_class' => InvoiceDiscount::class,

    'cascade_invoice_delete_to_invoice_items' => true,

    'serial_number' => [
        /**
         * If true, will generate a serial number on creation
         * If false, you will have to set the serial_number yourself
         */
        'auto_generate' => true,

        /**
         * Define the serial number format used for each invoice type
         *
         * P: Prefix
         * S: Serie
         * M: Month
         * Y: Year
         * C: Count
         * Example: IN0012-220234
         * Repeat letter to set the length of each information
         * Examples of formats:
         * - PPYYCCCC : IN220123 (default)
         * - PPPYYCCCC : INV220123
         * - PPSSSS-YYCCCC : INV0001-220123
         * - SSSS-CCCC: 0001-0123
         * - YYCCCC: 220123
         */
        'format' => 'PPYYCCCC',

        /**
         * Define the default prefix used for each invoice type
         */
        'prefix' => [
            InvoiceType::Invoice->value => 'IN',
            InvoiceType::Quote->value => 'QO',
            InvoiceType::Credit->value => 'CR',
            InvoiceType::Proforma->value => 'PF',
        ],

    ],

    'date_format' => 'Y-m-d',

    'rounding_mode' => RoundingMode::HALF_UP,

    'default_seller' => [
        'company' => null,
        'name' => null,
        'address' => [
            'street' => null,
            'city' => null,
            'postal_code' => null,
            'state' => null,
            'country' => null,
        ],
        'email' => null,
        'phone' => null,
        'tax_number' => null,
        'fields' => [
            //
        ],
    ],

    /**
     * ISO 4217 currency code
     */
    'default_currency' => 'USD',

    'pdf' => [

        'paper' => [
            'size' => 'a4',
            'orientation' => 'portrait',
        ],

        /**
         * Default DOM PDF options
         *
         * @see Available options https://github.com/barryvdh/laravel-dompdf#configuration
         */
        'options' => [
            // Required to load external CSS or images (e.g., from a URL or storage path)
            'isRemoteEnabled' => true,

            // Security: Keep false unless you specifically need to execute PHP inside the PDF template
            'isPhpEnabled' => false,

            // Adjusts line-height rendering to prevent text from looking vertically "cramped"
            'fontHeightRatio' => 0.8,

            /**
             * Supported values are: 'DejaVu Sans', 'Helvetica', 'Courier', 'Times', 'Symbol', 'ZapfDingbats'.
             */
            'defaultFont' => 'Helvetica',

            // Custom font storage: Required if using Google Fonts
            'fontDir' => storage_path('app/dompdf'),
            'fontCache' => storage_path('app/dompdf'),

            // System paths for temporary file processing and security boundaries
            'tempDir' => sys_get_temp_dir(),
            'chroot' => realpath(base_path()), // Limits Dompdf's file access to the project root
        ],

        /**
         * The logo displayed in the PDF
         */
        'logo' => null,

        /**
         * The template used to render the PDF
         */
        'template' => 'default.layout',

        'template_data' => [
            /**
             * The color used for the PDF header/accent.
             */
            'color' => '#050038',

            /**
             * The CSS font-family name.
             *
             * Note: 'Arimo' is recommended as it provides superior symbol support
             * compared to Helvetica, while maintaining a similar aesthetic.
             */
            'font' => null,

            /**
             * List of Google Font URLs to be imported into the document.
             */
            'fonts' => [
                // 'https://fonts.googleapis.com/css2?family=Arimo:ital,wght@0,400..700;1,400..700&display=swap',
            ],
        ],

    ],

];
```

The `PdfInvoice` Class
----------------------

[](#the-pdfinvoice-class)

This package provides a powerful, standalone `PdfInvoice` class. Its main functionalities include the ability to:

- Display your invoice as a PDF document.
- Render your invoice within a Blade view.

The `PdfInvoice` class is also integrated with the `Invoice` Eloquent Model, allowing you to easily convert an `Invoice` model instance into its PDF representation.

You can even use this package exclusively for the `PdfInvoice` class if you don't require database storage for your invoices.

### Full Example

[](#full-example)

```
use \Elegantly\Invoices\Pdf\PdfInvoice;
use \Elegantly\Invoices\Pdf\PdfInvoiceItem;
use \Elegantly\Invoices\Support\Seller;
use \Elegantly\Invoices\Support\Buyer;
use \Elegantly\Invoices\Support\Address;
use \Elegantly\Invoices\Support\PaymentInstruction;
use \Elegantly\Invoices\InvoiceDiscount;
use Brick\Money\Money;

$pdfInvoice = new PdfInvoice(
    name: "Invoice",
    state: "paid",
    serial_number: "INV-241200001",
    seller: new Seller(
        company: 'elegantly',
        name: 'Quentin Gabriele', // (optional)
        address: new Address(
            street: "Place de l'Opéra",
            city: 'Paris',
            postal_code: '75009',
            country: 'France',
        ),
        email: 'john.doe@example.com',
        tax_number: 'FR123456789',
        fields: [
            // Custom fields to display with the seller
            "foo" => "bar"
        ]
    ),
    buyer: new Buyer(
        company: "Doe Corporation" // (optional)
        name: 'John Doe', // (optional)
        address: new Address(
            street: '8405 Old James St.Rochester',
            city: 'New York',
            postal_code: '14609',
            state: 'NY',
            country: 'United States',
        ),
        shipping_address: new Address( // (optional)
            street: [ // multiple lines street
                '8405 Old James St.Rochester',
                'Apartment 1',
            ],
            city: 'New York',
            postal_code: '14609',
            state: 'NY',
            country: 'United States',
        ),
        email: 'john.doe@example.com',
        fields: [
            // Custom fields to display with the buyer
            "foo" => "bar"
        ]
    ),
    description: "An invoice description",
    created_at: now(),
    due_at: now(),
    paid_at: now(),
    tax_label: "VAT France (20%)",
    fields: [ // custom fields to display at the top
        'Order' => "PO0234"
    ],
    items: [
        new PdfInvoiceItem(
            label: "Laratranslate Unlimitted" ,
            unit_price: Money::of(99.0, 'USD'),
            tax_percentage: 20.0,
            quantity: 1,
            description: "Elegant All-in-One Translations Manager for Laravel",
        ),
    ],
    discounts: [
        new InvoiceDiscount(
            name: "Summer offer",
            code: "SUMMER",
            percent_off: 50,
        )
    ],
    paymentInstructions: [
        new PaymentInstruction(
            name: 'Bank Transfer',
            description: 'Make a direct bank transfer using the details below.',
            qrcode: 'data:image/png;base64,' . base64_encode(
                file_get_contents(__DIR__.'/../resources/images/qrcode.png')
            ),
            fields: [
                'Bank Name' => 'Acme Bank',
                'Account Number' => '12345678',
                'IBAN' => 'GB12ACME12345678123456',
                'SWIFT/BIC' => 'ACMEGB2L',
                'Reference' => 'INV-0032/001',
                'Pay online',
            ],
        ),
    ],
    logo: public_path('/images/logo.png'), // local path or base64 string
    template: "default.layout", // use the default template or use your own
    templateData: [ // custom data to pass to the template
        'color' => '#050038'
    ],
);
```

### Rendering the Invoice as a PDF

[](#rendering-the-invoice-as-a-pdf)

```
namespace App\Http\Controllers;

use Elegantly\Invoices\Pdf\PdfInvoice;

class InvoiceController extends Controller
{
    public function showAsPdf()
    {
        $pdfInvoice = new PdfInvoice(
            // ...
        );

        return $pdfInvoice->stream();
    }
}
```

### Storing the PDF in a file

[](#storing-the-pdf-in-a-file)

```
namespace App\Http\Controllers;

use Elegantly\Invoices\Pdf\PdfInvoice;
use Illuminate\Support\Facades\Storage;

class InvoiceController extends Controller
{
    public function store()
    {
        $pdfInvoice = new PdfInvoice(
            // ...
        );

        Storage::put(
            "path/to/{$pdfInvoice->getFilename()}",
            $pdfInvoice->getPdfOutput()
        );

        // ...
    }
}
```

### Downloading the Invoice as a PDF

[](#downloading-the-invoice-as-a-pdf)

#### From a controller

[](#from-a-controller)

To download the PDF, simply return the `download` method.

```
namespace App\Http\Controllers;

use Elegantly\Invoices\Pdf\PdfInvoice;

class InvoiceController extends Controller
{
    public function download()
    {
        $pdfInvoice = new PdfInvoice(
            // ...
        );

        return $pdfInvoice->download(
            /**
             * (optional)
             * The default filename is the serial_number
             */
            filename: 'invoice.pdf'
        );
    }
}
```

#### From a Livewire component

[](#from-a-livewire-component)

To download the PDF from a Livewire component, use the `streamDownload` method as shown below:

```
namespace App\Http\Controllers;

use Elegantly\Invoices\Pdf\PdfInvoice;

class Invoice extends Component
{
    public function download()
    {
        $pdfInvoice = new PdfInvoice(
            // ...
        );

        return response()->streamDownload(function () use ($pdfInvoice) {
            echo $pdf->getPdfOutput();
        }, $pdf->getFilename()); // The default filename is the serial number
    }
}
```

### Rendering the Invoice as a view

[](#rendering-the-invoice-as-a-view)

```
namespace App\Http\Controllers;

use Elegantly\Invoices\Pdf\PdfInvoice;

class InvoiceController extends Controller
{
    public function showAsView()
    {
        $pdfInvoice = new PdfInvoice(
            // ...
        );

        return $pdfInvoice->view();
    }
}
```

### Rendering the Invoice within a View

[](#rendering-the-invoice-within-a-view)

You can embed the invoice within a larger Blade view to create interfaces like an "invoice builder," similar to the [interactive demo](https://elegantly.devlaravel-invoices).

To do this, include the main invoice partial in your view as shown below:

```

    @include('invoices::default.invoice', ['invoice' => $invoice])

```

This approach allows for seamless integration of the invoice into a dynamic and customizable user interface.

Note

The default template uses Tailwind CSS for styling. This ensures seamless integration with websites already using Tailwind. If your project doesn't use Tailwind, the invoice styling may not appear as intended.

### Adding Taxes

[](#adding-taxes)

Taxes are applied to individual `PdfInvoiceItem` item. You can define them either as a percentage or a fixed amount.

#### Tax by Percentage

[](#tax-by-percentage)

To add a tax as a percentage, set the `tax_percentage` property on the `PdfInvoiceItem`. This value should be a float between 0 and 100.

```
use \Elegantly\Invoices\Pdf\PdfInvoiceItem;

new PdfInvoiceItem(
    label: "Laratranslate Unlimitted" ,
    unit_price: Money::of(99.0, 'USD'),
    tax_percentage: 20.0, // a float between 0.0 and 100.0
),
```

#### Tax as a Fixed Amount

[](#tax-as-a-fixed-amount)

To apply a tax as a specific monetary amount, set the `unit_tax` property on the `PdfInvoiceItem`.

```
use \Elegantly\Invoices\Pdf\PdfInvoiceItem;

new PdfInvoiceItem(
    label: "Laratranslate Unlimitted" ,
    unit_price: Money::of(99.0, 'USD'),
    unit_tax: Money::of(19.8, 'USD'),
),
```

### Adding Discounts

[](#adding-discounts)

Discounts are represented by the `InvoiceDiscount` class and are applied to the entire `PdfInvoice`. They cannot be attached to individual `PdfInvoiceItem`s at this time.

- You can add multiple discounts to a single invoice.
- Discounts can be specified as a fixed amount (`amount_off`) or a percentage (`percent_off`). If both are provided for the same discount, the `amount_off` value takes precedence.

#### Discount by Percentage

[](#discount-by-percentage)

To apply a discount as a percentage, set the `percent_off` property.

```
use \Elegantly\Invoices\Pdf\PdfInvoice;
use \Elegantly\Invoices\InvoiceDiscount;
use Brick\Money\Money;

$pdfInvoice = new PdfInvoice(
    // ...
    discounts: [
        new InvoiceDiscount(
            name: "Summer offer",
            code: "SUMMER",
            percent_off: 20.0,
        )
    ],
);
```

#### Discount as a Fixed Amount

[](#discount-as-a-fixed-amount)

To apply a discount as a fixed amount, set the `amount_off` property.

```
use \Elegantly\Invoices\Pdf\PdfInvoice;
use \Elegantly\Invoices\InvoiceDiscount;
use Brick\Money\Money;

$pdfInvoice = new PdfInvoice(
    // ...
    discounts: [
        new InvoiceDiscount(
            name: "Summer offer",
            code: "SUMMER",
            amount_off: Money::of(20.0, 'USD'),
        )
    ],
);
```

### Adding Payment Instructions

[](#adding-payment-instructions)

You can include detailed payment instructions directly within the generated PDF invoice. This can be helpful for providing bank transfer details, QR codes for quick payments, and custom payment links.

Here’s an example of how to add a payment instruction:

```
use \Elegantly\Invoices\Pdf\PdfInvoice;
use \Elegantly\Invoices\Support\PaymentInstruction;

$pdfInvoice = new PdfInvoice(
    // ...
    paymentInstructions: [
        new PaymentInstruction(
            name: 'Bank Transfer',
            description: 'Make a direct bank transfer using the details below.',
            qrcode: 'data:image/png;base64,' . base64_encode(
                file_get_contents(__DIR__.'/../resources/images/qrcode.png')
            ),
            fields: [
                'Bank Name' => 'Acme Bank',
                'Account Number' => '12345678',
                'IBAN' => 'GB12ACME12345678123456',
                'SWIFT/BIC' => 'ACMEGB2L',
                'Reference' => 'INV-0032/001',
                'Pay online',
            ],
        ),
    ]
);
```

> **Note:** You can include HTML tags (e.g., links) within the `fields` array for interactive content.

#### QR Code Generation

[](#qr-code-generation)

To dynamically generate QR codes, I recommend using the [`chillerlan/php-qrcode`](https://github.com/chillerlan/php-qrcode) package. It provides a simple and flexible API for generating QR codes in various formats.

### Customization

[](#customization)

#### Customizing Fonts

[](#customizing-fonts)

See the [Dompdf font guide](https://github.com/dompdf/dompdf/wiki/About-Fonts-and-Character-Encoding).

#### Customizing the Invoice Template

[](#customizing-the-invoice-template)

To customize the invoice template, first publish the package's views:

```
php artisan vendor:publish --tag="invoices-views"
```

After publishing, you can modify the Blade files in `resources/views/vendor/invoices/` to suit your needs.

Note

If you introduce new CSS classes in your custom template, ensure you define their styles in the style.blade.php file.

Alternatively, to use a completely different custom template, you can specify its path in the configuration file:

Warning

Your custom template file must be in `resources/views/vendor/invoices`

```
return [

    // ...

    'pdf' => [

        /**
         * The template used to render the PDF
         */
        'template' => 'my-custom.layout',

        'template_data' => [
            /**
             * The color displayed at the top of the PDF
             */
            'color' => '#050038',
        ],

    ],

];
```

Ensure that your custom template follows the same structure and conventions as the default one to maintain compatibility with various use cases.

The `Invoice` Eloquent Model
----------------------------

[](#the-invoice-eloquent-model)

The design of the `Invoice` Eloquent Model closely mirrors that of the `PdfInvoice` class.

This model provides powerful features for:

- Generating unique and complex serial numbers.
- Attaching your invoice to any other Eloquent model.
- Easily including your invoice as an attachment in emails.

Note

Remember to publish and run the database migrations

### Complete Example

[](#complete-example)

The following example demonstrates how to create and store an invoice.

For this illustration, let's assume the following application structure:

- `Team` models have `User` models.
- `Team` models can have multiple `Invoice` models.
- `Invoice` models can be attached to `Order` models.

```
use App\Models\Team;
use App\Models\Order;

use Brick\Money\Money;
use Elegantly\Invoices\Models\Invoice;
use Elegantly\Invoices\Enums\InvoiceState;
use Elegantly\Invoices\Enums\InvoiceType;

$customer = Team::find(1);
$order = Order::find(2);

$invoice = new Invoice(
    'type' => "invoice",
    'state' => "paid",
    'seller_information' => config('invoices.default_seller'),
    'buyer_information' =>[
        'company' => "Doe Corporation" // (optional)
        'name' => 'John Doe', // (optional)
        'address' => [
            'street' => '8405 Old James St.Rochester',
            'city' => 'New York',
            'postal_code' => '14609',
            'state' => 'NY',
            'country' => 'United States',
        ],
        'shipping_address' => [ // (optional)
            'street' => [ // multiple lines street
                '8405 Old James St.Rochester',
                'Apartment 1',
            ],
            'city' => 'New York',
            'postal_code' => '14609',
            'state' => 'NY',
            'country' => 'United States',
        ]
        'email' => 'john.doe@example.com',
        'fields' => [
            // Custom fields to display with the buyer
            "foo" => "bar"
        ]
    ],
    'description' => "An invoice description",
    'due_at' => now(),
    'paid_at' => now(),
    'tax_type' => "eu_VAT_FR",
    'tax_exempt' => null,
);

// Learn more about the serial number in the next section
$invoice->configureSerialNumber(
    prefix: "ORD",
    serie: $customer->id,
    year: now()->format('Y'),
    month: now()->format('m')
);

// Optional
// Learn more about the logo in the next section
$invoice->setLogoFromConfig();

$invoice->buyer()->associate($customer); // optionnally associate the invoice to any model
$invoice->invoiceable()->associate($order); // optionnally associate the invoice to any model

$invoice->save();

$invoice->items()->saveMany([
    new InvoiceItem([
        'label' => "Laratranslate Unlimitted",
        'description' => "Elegant All-in-One Translations Manager for Laravel",
        'unit_price' => Money::of(99.0, 'USD'),
        'tax_percentage' => 20.0,
        'quantity' => 1,
    ]),
]);
```

### Generating Unique Serial Numbers

[](#generating-unique-serial-numbers)

This package provides a simple and reliable way to generate serial numbers automatically, such as "INV240001".

You can configure the format of your serial numbers in the configuration file. The default format is `PPYYCCCC`, where each letter has a specific meaning (see the config file for details).

When `invoices.serial_number.auto_generate` is set to `true`, a unique serial number is assigned to each new invoice automatically.

Serial numbers are generated sequentially, with each new serial number based on the latest available one. To define what qualifies as the `previous` serial number, you can extend the `Elegantly\Invoices\Models\Invoice` class and override the `getPreviousInvoice` method.

By default, the previous invoice is determined based on criteria such as prefix, series, year, and month for accurate, scoped numbering.

### Using Multiple Prefixes and Series for Serial Numbers

[](#using-multiple-prefixes-and-series-for-serial-numbers)

In more complex applications, you may need to use different prefixes and/or series for your invoices.

For instance, you might want to define a unique series for each user, creating serial numbers that look like: `INV0001-2400X`, where `0001` represents the user’s ID, `24` the year and `X` the index of the invoice.

Note

When using IDs for series, it's recommended to plan for future growth to avoid overflow. Even if you have a limited number of users now, ensure that the ID can accommodate the maximum number of digits allowed by the serial number format.

When creating an invoice, you can dynamically specify the prefix and series with `configureSerialNumber` method:

```
use Elegantly\Invoices\Models\Invoice;

$invoice = new Invoice();

$invoice->configureSerialNumber(
    prefix: "ORG",
    serie: $buyerId,
);
```

### Customizing the Serial Number Format

[](#customizing-the-serial-number-format)

In most cases, the format of your serial numbers should remain consistent, so it's recommended to set it in the configuration file.

The format you choose will determine the types of information you need to provide to `configureSerialNumber`.

Below is an example of the most complex serial number format you can create with this package:

```
use Elegantly\Invoices\Models\Invoice;

$invoice = new Invoice();

$invoice->configureSerialNumber(
    format: "PP-SSSSSS-YYMMCCCC",
    prefix: "IN",
    serie: 100,
    year: now()->format('Y'),
    month: now()->format('m')
);

$invoice->save();

$invoice->serial_number; // IN-000100-24010001
```

### Storing the Logo

[](#storing-the-logo)

By default, the PDF logo is loaded from the configuration defined in your config file.

If you want the logo to remain consistent over time, even if the config changes, you can store it directly in the database:

```
use Elegantly\Invoices\Models\Invoice;

$invoice = new Invoice();

// Store the current config logo in the database
$invoice->setLogoFromConfig();

// ...

$invoice->save();
```

### Storing a Dynamic Logo

[](#storing-a-dynamic-logo)

If your application allows users to upload or select their own company logos, you can dynamically set the logo on each invoice by updating the `logo` attribute on the `Invoice` model.

You can do this in several ways:

```
use Elegantly\Invoices\Models\Invoice;

$invoice = new Invoice();

// Set the logo from an uploaded file (e.g., Illuminate\Http\UploadedFile)
$invoice->setLogoFromFile($file);

// Set the logo from a local filesystem path
$invoice->setLogoFromPath($path);

// Set the logo directly from raw file content (string or binary data)
$invoice->logo = $rawFileContent;

// ...

$invoice->save();
```

### Converting an `Invoice` Model to a `PdfInvoice`

[](#converting-an-invoice-model-to-a-pdfinvoice)

You can obtained a `PdfInvoice` class from your `Invoice` model by calling the `toPdfInvoice` method:

```
$invoice = Invoice::first();

$pdfInvoice = $invoice->toPdfInvoice();
```

### Display, Download, and Store Invoices

[](#display-download-and-store-invoices)

You can then stream the `PdfInvoice` instance directly or initiate a download:

```
namespace App\Http\Controllers;

use App\Models\Invoice;
use Illuminate\Http\Request;

class InvoiceController extends Controller
{
    public function show(Request $request, string $serial)
    {
        /** @var Invoice $invoice */
        $invoice = Invoice::where('serial_number', $serial)->firstOrFail();

        $this->authorize('view', $invoice);

        return $invoice->toPdfInvoice()->stream();
    }

    public function download(Request $request, string $serial)
    {
        /** @var Invoice $invoice */
        $invoice = Invoice::where('serial_number', $serial)->firstOrFail();

        $this->authorize('view', $invoice);

        return $invoice->toPdfInvoice()->download();
    }

    public function store(Request $request, string $serial)
    {
        /** @var Invoice $invoice */
        $invoice = Invoice::where('serial_number', $serial)->firstOrFail();

        Storage::put(
            "path/to/invoice.pdf",
            $invoice->toPdfInvoice()->getPdfOutput()
        );

        // ...
    }
}
```

### Attaching Invoices to Mailables

[](#attaching-invoices-to-mailables)

You can easily attach an invoice to your `Mailable` as follows:

```
namespace App\Mail;

use App\Models\Invoice;
use Illuminate\Bus\Queueable;
use Illuminate\Mail\Mailable;
use Illuminate\Queue\SerializesModels;

class PaymentInvoice extends Mailable
{
    use Queueable, SerializesModels;

    /**
     * Create a new message instance.
     */
    public function __construct(
        protected Invoice $invoice,
    ) {}

    public function attachments(): array
    {
        return [
            $this->invoice->toMailAttachment()
        ];
    }
}
```

### Attaching Invoices to Notifications

[](#attaching-invoices-to-notifications)

You can easily attach an invoice to your `Notification` as follows:

```
namespace App\Mail;

use App\Models\Invoice;
use Illuminate\Bus\Queueable;
use Illuminate\Notifications\Notification;
use Illuminate\Notifications\Messages\MailMessage;

class PaymentInvoice extends Notification implements ShouldQueue
{
    use Queueable;

    /**
     * Create a new message instance.
     */
    public function __construct(
        protected Invoice $invoice,
    ) {}

    public function toMail($notifiable)
    {
        return (new MailMessage)
            ->attach($this->invoice);
    }
}
```

### Customizing PDF Output from the Model

[](#customizing-pdf-output-from-the-model)

To customize how your `Invoice` model is converted into a `PdfInvoice` object, follow these steps:

1. **Create a Custom Invoice Model**:

Define your own `App\Models\Invoice` class and ensure it extends the base `Elegantly\Invoices\Models\Invoice`.

```
namespace App\Models;

class Invoice extends \Elegantly\Invoices\Models\Invoice
{
    // ...
}
```

2. **Override the `toPdfInvoice` Method**:

In your custom `Invoice` model, override the `toPdfInvoice` method. This is where you'll implement your specific logic to construct and return the `PdfInvoice` object with your desired customizations.

```
namespace App\Models;

use Elegantly\Invoices\Pdf\PdfInvoice;

class Invoice extends \Elegantly\Invoices\Models\Invoice
{
    function toPdfInvoice(): PdfInvoice
    {
        return new PdfInvoice(
            // ... your custom PdfInvoice properties and configuration
        );
    }
}
```

3. **Update the Package Configuration**:

First, if you haven't already, publish the package's configuration file:

```
php artisan vendor:publish --tag="invoices-config"
```

Then, modify the `config/invoices.php` file to tell the package to use your custom model by updating the `model_invoice` key:

```
return [
    // ...

    'model_invoice' => \App\Models\Invoice::class,

    // ...
];
```

#### Using a Custom PdfInvoice Class

[](#using-a-custom-pdfinvoice-class)

You can extend the default PdfInvoice class provided by the package to customize its behavior, such as changing the generated filename or adding additional logic.

1. Create Your Custom PdfInvoice Class

```
class PdfInvoice extends \Elegantly\Invoices\Pdf\PdfInvoice
{

    public function __construct(
        // your custom constructor
    ){
        // ...
    }

    public function getFilename(): string
    {
        return str($this->serial_number)
            ->replace(['/', '\\'], '_')
            ->append('.pdf')
            ->value();
    }
}
```

In this example, we're overriding the `getFilename` method.

2. Return Your Custom `PdfInvoice` from the Invoice Model

Update your `Invoice` model to return an instance of your custom `PdfInvoice` class.

```
namespace App\Models;

use App\ValueObjects\PdfInvoice;

class Invoice extends \Elegantly\Invoices\Models\Invoice
{
    function toPdfInvoice(): PdfInvoice
    {
        return new PdfInvoice(
            // Pass any required data to your custom PdfInvoice constructor
        );
    }
}
```

By overriding the `toPdfInvoice` method, you can inject your custom logic while preserving compatibility with the rest of the package.

### Casting `state` and `type` to Enums

[](#casting-state-and-type-to-enums)

By default, the `type` and `state` properties on the `Invoice` model are stored as strings. This approach offers flexibility, as it doesn't restrict you to predefined values and they are not automatically cast to Enum objects.

However, you might prefer to cast these properties to Enum objects for better type safety and code clarity. You can use your own custom Enums or the ones provided by this package (e.g., `Elegantly\Invoices\Enums\InvoiceState`, `Elegantly\Invoices\Enums\InvoiceType`).

To enable Enum casting for these properties, follow these steps:

1. **Create custom `InvoiceState` and `InvoiceType` Enums** (optional):

If you're working with commonly used invoice states and types, you can use the enums provided by this package:

- `Elegantly\Invoices\Enums\InvoiceState`
- `Elegantly\Invoices\Enums\InvoiceType`

For custom states or types, you can define your own enums.

Make sure your custom enums implement the `Elegantly\Invoices\Contracts\HasLabel` contract, like so:

```
namespace App\Enums;

use Elegantly\Invoices\Contracts\HasLabel;

enum InvoiceType: string implements HasLabel
{
    case Invoice = 'invoice';
    case Quote = 'quote';
    case Credit = 'credit';
    case Proforma = 'proforma';

    public function getLabel(): string
    {
        return match ($this) {
            self::Invoice => __('invoices::invoice.types.invoice'),
            self::Quote => __('invoices::invoice.types.quote'),
            self::Credit => __('invoices::invoice.types.credit'),
            self::Proforma => __('invoices::invoice.types.proforma'),
        };
    }
}
```

1. **Create a Custom `Invoice` Model**:

Define your own `App\Models\Invoice` class that extends `\Elegantly\Invoices\Models\Invoice`. In this custom model, override the `casts()` method to specify the Enum classes for the `type` and `state` attributes.

```
namespace App\Models;

use Elegantly\Invoices\Enums\InvoiceState;
use Elegantly\Invoices\Enums\InvoiceType;

/**
 * @property InvoiceType $type
 * @property InvoiceState $state
 */
class Invoice extends \Elegantly\Invoices\Models\Invoice
{
    protected $attributes = [
        'type' => InvoiceType::Invoice->value,
        'state' => InvoiceState::Draft->value,
    ];

    protected function casts(): array
    {
        return [
            ...parent::casts(), // Merge with parent casts for other potential attributes
            'type' => InvoiceType::class,
            'state' => InvoiceState::class,
        ];
    }
}
```

2. **Publish Package Configuration**:

If you haven't already, publish the package's configuration file:

```
php artisan vendor:publish --tag="invoices-config"
```

3. **Update Configuration to Use Your Custom Model**:

Modify the `config/invoices.php` file and update the `model_invoice` key to point to your newly created custom `Invoice` model:

```
return [
    // ...

    'model_invoice' => \App\Models\Invoice::class,

    // ...
];
```

Testing
-------

[](#testing)

```
composer test
```

Changelog
---------

[](#changelog)

Please see [CHANGELOG](CHANGELOG.md) for more information on what has changed recently.

Contributing
------------

[](#contributing)

Please see [CONTRIBUTING](CONTRIBUTING.md) for details.

Security Vulnerabilities
------------------------

[](#security-vulnerabilities)

Please review [our security policy](../../security/policy) on how to report security vulnerabilities.

Credits
-------

[](#credits)

- [Quentin Gabriele](https://github.com/QuentinGab)
- [All Contributors](../../contributors)

License
-------

[](#license)

The MIT License (MIT). Please see [License File](LICENSE.md) for more information.

###  Health Score

60

—

FairBetter than 99% of packages

Maintenance88

Actively maintained with recent releases

Popularity44

Moderate usage in the ecosystem

Community22

Small or concentrated contributor base

Maturity71

Established project with proven stability

 Bus Factor1

Top contributor holds 82.5% of commits — single point of failure

How is this calculated?**Maintenance (25%)** — Last commit recency, latest release date, and issue-to-star ratio. Uses a 2-year decay window.

**Popularity (30%)** — Total and monthly downloads, GitHub stars, and forks. Logarithmic scaling prevents top-heavy scores.

**Community (15%)** — Contributors, dependents, forks, watchers, and maintainers. Measures real ecosystem engagement.

**Maturity (30%)** — Project age, version count, PHP version support, and release stability.

###  Release Activity

Cadence

Every ~13 days

Recently: every ~5 days

Total

92

Last Release

70d ago

Major Versions

v0.1.0 → v1.0.02023-02-16

v0.1.x-dev → v1.0.22023-03-04

v1.0.4 → v2.0.02023-05-17

v2.3.7 → v3.0.02024-03-26

v3.5.5 → v4.0.02025-03-06

### Community

Maintainers

![](https://www.gravatar.com/avatar/d769563728757858e249f266ac2555f28db5640124df92821ed17d93ee76fc7b?d=identicon)[QuentinGab](/maintainers/QuentinGab)

---

Top Contributors

[![QuentinGab](https://avatars.githubusercontent.com/u/40128136?v=4)](https://github.com/QuentinGab "QuentinGab (255 commits)")[![dependabot[bot]](https://avatars.githubusercontent.com/in/29110?v=4)](https://github.com/dependabot[bot] "dependabot[bot] (27 commits)")[![github-actions[bot]](https://avatars.githubusercontent.com/in/15368?v=4)](https://github.com/github-actions[bot] "github-actions[bot] (16 commits)")[![teodino93](https://avatars.githubusercontent.com/u/1943125?v=4)](https://github.com/teodino93 "teodino93 (2 commits)")[![emirq](https://avatars.githubusercontent.com/u/9058700?v=4)](https://github.com/emirq "emirq (2 commits)")[![michelmelo](https://avatars.githubusercontent.com/u/159223?v=4)](https://github.com/michelmelo "michelmelo (2 commits)")[![maatien](https://avatars.githubusercontent.com/u/420445?v=4)](https://github.com/maatien "maatien (1 commits)")[![bizexcel](https://avatars.githubusercontent.com/u/46524294?v=4)](https://github.com/bizexcel "bizexcel (1 commits)")[![emaadali](https://avatars.githubusercontent.com/u/3521616?v=4)](https://github.com/emaadali "emaadali (1 commits)")[![sdebacker](https://avatars.githubusercontent.com/u/134503?v=4)](https://github.com/sdebacker "sdebacker (1 commits)")[![Gamzky](https://avatars.githubusercontent.com/u/30494798?v=4)](https://github.com/Gamzky "Gamzky (1 commits)")

---

Tags

invoice-generatorinvoicesinvoices-pdflaravelpdfphplaravelinvoicesElegantlylaravel-invoices

###  Code Quality

TestsPest

Static AnalysisPHPStan

Code StyleLaravel Pint

### Embed Badge

![Health badge](/badges/finller-laravel-invoices/health.svg)

```
[![Health](https://phpackages.com/badges/finller-laravel-invoices/health.svg)](https://phpackages.com/packages/finller-laravel-invoices)
```

###  Alternatives

[elegantly/laravel-invoices

Store invoices safely in your Laravel application

23131.8k](/packages/elegantly-laravel-invoices)[spatie/laravel-pdf

Create PDFs in Laravel apps

9963.4M12](/packages/spatie-laravel-pdf)[consoletvs/invoices

Generate PDF invoices for your customers in laravel

455275.5k](/packages/consoletvs-invoices)[vormkracht10/laravel-mails

Laravel Mails can collect everything you might want to track about the mails that has been sent by your Laravel app.

24149.7k](/packages/vormkracht10-laravel-mails)[elegantly/laravel-translator

All on one translations management for Laravel

6216.9k](/packages/elegantly-laravel-translator)[finller/laravel-media

A flexible media library for Laravel

472.1k](/packages/finller-laravel-media)

PHPackages © 2026

[Directory](/)[Categories](/categories)[Trending](/trending)[Changelog](/changelog)[Analyze](/analyze)
