Weave Code
Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Tomato Invoices Laravel Package

tomatophp/tomato-invoices

Tomato Invoices is a Laravel package for creating, managing, and tracking invoices in TomatoPHP and Filament admin panels. Generate professional invoices with clients, line items, taxes, totals, statuses, and PDF-ready output from a streamlined billing interface.

View on GitHub
Deep Wiki
Context7

Getting Started

tomatophp/tomato-invoices is a Filament-oriented invoicing module from the TomatoPHP stack. It ships models, migrations, Filament resources, and (as of v1.0.5) an HTTP route surface for product/line-item handling.

Minimum path to a working install:

  1. composer require tomatophp/tomato-invoices — pin the constraint ("^1.0.5") rather than tracking dev-main; this is a fast-moving 1.x package.
  2. Publish and run the migrations before touching the panel:
    php artisan vendor:publish --tag=tomato-invoices-migrations
    php artisan vendor:publish --tag=tomato-invoices-config
    php artisan migrate
    
  3. Register the plugin with your Filament panel provider (->plugin(TomatoInvoicesPlugin::make())), then clear caches: php artisan optimize:clear.
  4. Seed or create one customer and one product, then create an invoice with a single line item from the Filament UI. That end-to-end pass is the fastest way to confirm the routes and resources are wired correctly on your Laravel/Filament version.

Where to look first: the published config (for table prefixes, model bindings, and disk settings), then the Filament resource classes for Invoice and Product. Those two resources define the day-to-day surface area far more than the models do.

First real use case: generate a draft invoice from a customer plus line items, render it to PDF, and store it on a configured disk. Get that working in a queue-safe way before building anything on top of it.

Implementation Patterns

Treat invoices as an aggregate, not a CRUD row. The invoice header, its line items, and its computed totals need to move together. Wrap creation and mutation in a transaction and recalculate totals from the line items rather than trusting a form-supplied total:

DB::transaction(function () use ($data) {
    $invoice = Invoice::create($header);
    $invoice->items()->createMany($data['items']);
    $invoice->recalculateTotals()->save();
});

Use observers for total recalculation. Hooking saved/deleted on the line-item model keeps totals correct regardless of whether the change came from Filament, a console command, or an import. This is the single highest-leverage integration point.

Model swapping over forking. TomatoPHP packages generally expose model class bindings in config. If you need tenant scoping or extra columns, bind your own subclass in config and add a migration for the extra fields — don't edit the vendor migrations, or every upgrade becomes a merge.

PDF generation belongs in a queued job. Rendering and uploading a PDF is slow and failure-prone (fonts, disk timeouts). Dispatch a job, store the file path on the invoice, and let the Filament action poll or notify. Keep the render path idempotent so retries don't produce duplicate files.

Extend Filament resources via configuration, not by copying. Where the package exposes form/table schema hooks, use them. Where it doesn't, subclass the resource and re-register it in your panel — this survives minor upgrades much better than editing the published resource in place.

Scope by tenant at the query level. If you're multi-tenant, apply a global scope to the invoice model early. Retrofitting tenancy after you have production invoice data is painful, and invoice numbering schemes usually need to become tenant-aware at the same time.

Keep an eye on the route layer. The v1.0.5 fix was a route correction for products, which means the HTTP surface is still settling. If you consume these routes directly (rather than through Filament), write a thin integration test that hits each endpoint you depend on, so a patch release that reshuffles a route name fails your CI rather than production.

Gotchas and Tips

  • Clear caches after every upgrade. A route fix like the one in v1.0.5 does nothing until route:clear (or optimize:clear) runs. On cached-route production deploys, this is the most common "the fix didn't work" report.
  • Publish before migrate, and re-check published files on upgrade. If you published migrations at v1.0.2 and the schema changed since, migrate won't pick up new vendor migrations. Diff the package's database/migrations against your published set on each minor bump.
  • Money handling. Confirm how the package stores amounts — if totals are decimal-cast floats rather than integer minor units, rounding drift will show up on taxed multi-line invoices. Verify with a three-line invoice at awkward percentages before you trust the numbers.
  • Invoice numbering races. Sequential numbering under concurrency needs a lock or a dedicated sequence table. Two simultaneous creates can both read the same "next" number. Test this with parallel requests, not by clicking twice.
  • Soft deletes and totals. Deleting a line item that soft-deletes won't fire deleted on some setups — use the appropriate model event or forceDeleted handling so totals don't silently go stale.
  • PDF environment issues. Font subsets, storage_path permissions, and non-default disks are the usual culprits for blank or missing PDFs. Test the render path in the same container image you deploy, not just locally.
  • Vendor churn is real. v1.0.5 is a one-line community contribution from a first-time contributor. That's healthy, but it also means the maintainer surface is thin and patch releases can land without deep review of downstream impact. Pin exact versions, read the compare diff before bumping, and keep the invoice models behind your own service layer so a rename upstream is a one-file change.
  • Debugging tip: when a Filament resource throws an opaque error, re-run with APP_DEBUG=true and check whether the failure is in the resource or in a policy. Missing policies on new resources are a frequent source of 403s that look like route bugs.
  • Extension points worth knowing: config-level model bindings, the Filament plugin registration (for navigation group, slug, and access control), and published views. Reach for these in that order before considering a fork.
Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
gmostafa/php-graphql-client
xeviant/paystack
snowsoft/faker
meditationsteps/blogetc
animalyoung/laravel-influxdb
onix-solutions/sms-telera
lonely-lights/prosetta
oxygen/data
oxygen/core
jengo/base
xiloryx/log-collector
a21ns1g4ts/filament-stripe
la-php/laravel-admin
artisan-build/community-prompts
vleroy/smart
ayles-software/laravel-australian-public-holidays
cboxdk/laravel-id-spatie
cboxdk/laravel-id-billing
cboxdk/laravel-id-billing-bridge
simple-as-fuck/php-performance-log