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

Circle Invoices Module Laravel Package

tomatophp/circle-invoices-module

Invoices module for TomatoPHP's Circle, adding invoice creation, line items, taxes, and status tracking to your Laravel app. Generate and manage billing records, attach them to Circle customers or subscriptions, and keep payment history organized in one place.

View on GitHub
Deep Wiki
Context7

Getting Started

v1.0.0 is the first tagged release of tomatophp/circle-invoices-module, a module in the TomatoPHP Circle ecosystem. Treat it as the invoice domain layer (models, migrations, Filament resources, policies) rather than a full billing engine — tax calculation, payment capture, and PDF branding are yours to supply.

  1. Confirm the host app is a Circle app. This module expects tomatophp/circle-core (and usually Filament) to already be installed and bootstrapped. Installing it into a plain Laravel app will leave you with orphaned resources and unresolved panel registration.
  2. Install and pin:
    composer require tomatophp/circle-invoices-module:1.0.0
    
    Pin the exact version — there's no upgrade guide yet, and 1.0.x patches may still touch schema.
  3. Publish and migrate. TomatoPHP modules conventionally expose tagged publishes; check the README for exact tags, but the sequence is:
    php artisan vendor:publish --tag="circle-invoices-module-config"
    php artisan vendor:publish --tag="circle-invoices-module-migrations"
    php artisan migrate
    
  4. Where to look first: the module's src/Providers/*ServiceProvider.php (what it registers, what's bindable in the container), the database/migrations/ folder (the real contract — invoice header vs. line-item tables, money column types, status column), then the Filament resource under src/Filament/.
  5. First use case: create an invoice for an existing customer/order, attach two line items, and verify totals are recomputed server-side. Do this in php artisan tinker before touching the UI — it surfaces the model's guarded fields, casts, and required relations fastest.

Implementation Patterns

Write through a service, not the model. The module owns persistence; your app should own the workflow. Wrap invoice creation in an action class so numbering, totals, and status transitions happen in one transaction:

DB::transaction(function () use ($order) {
    $invoice = app(CreateInvoice::class)->for($order->customer, $order->currency);
    foreach ($order->lines as $line) {
        $invoice->items()->create([...]);
    }
    $invoice->recalculateTotals();
});

Drive it from domain events. The cleanest day-to-day integration is a listener on your own OrderPlaced / SubscriptionRenewed event that creates a draft invoice. Keep the module's models out of your controllers entirely; that way a future major version changing the API only breaks one listener.

Status is a state machine, not a boolean. Map out draft → sent → paid → void (whatever the migration's enum/status column actually allows) up front and enforce it in one place — an observer or a dedicated InvoiceStatus enum with canTransitionTo(). Do not let Filament actions and your API both write status directly, or you'll end up with paid invoices that still have a sent_at of null.

Numbering. Invoice numbers must be gapless-looking and unique under concurrency. Put generation behind a single service or model observer, back it with a DB unique index, and catch the duplicate-key exception with a retry loop. Never generate from count() + 1.

Extend the Filament resource, don't edit it. Register your own resource that extends the module's and override table(), form(), and getNavigationGroup(). Vendor edits vanish on composer update.

Queue the expensive bits. PDF rendering and mail delivery belong in jobs dispatched from an observer on the "invoice issued" transition, so the HTTP request that creates an invoice stays fast and idempotent.

Multi-tenant scoping. If your Circle app uses teams/companies, add a global scope on the invoice model early — retrofitting tenancy after you have invoices in the wild is painful.

Gotchas and Tips

  • No migration guide in v1.0.0. The release notes are a bare changelog link. If you've been tracking dev-main, diff your published migrations against the tagged ones before upgrading — published migrations are copied, so composer update will not bring schema changes to your app.
  • Provider order matters. In Laravel 11's bootstrap/providers.php, the Circle core provider must be registered before this module, otherwise panel/resource registration silently no-ops. Symptom: the module is installed, migrations ran, but no menu item appears.
  • Config caching. Publish the config, edit it, then php artisan config:clear. A cached config during local development is the single most common "my setting is ignored" report.
  • Money columns. Check the migration for decimal vs. bigInteger minor units before writing a single line of code. If they're decimals, cast to a money value object immediately and never do arithmetic on the raw attribute; if integers, be explicit about the exponent in every formatter.
  • Never trust posted totals. Filament forms and API requests can both submit a total. Recompute from line items in a saving hook and overwrite whatever came in.
  • Unique number + soft deletes. A unique index on number combined with soft-deleted invoices means a voided-then-deleted invoice permanently burns its number, or worse, blocks reissue. Either exclude deleted_at rows via a partial index or use a separate sequence table.
  • Debugging checklist: php artisan about (providers loaded), php artisan route:list | grep -i invoice, php artisan event:list | grep -i invoice, php artisan migrate:status | grep invoice. Between those four you can localise almost any "it's installed but not working" issue.
  • Testing. Use RefreshDatabase, the module's factories, and Carbon::setTestNow() when asserting due dates and overdue logic — otherwise your test suite will start failing on month boundaries.
  • Extension points to check for: whether the invoice-number generator, PDF renderer, and total calculator are resolved from the container. If they are, bind your own implementations in a service provider and leave the module untouched. If they aren't, this is worth an upstream issue — and until then, observers are your only hook.
  • Version pinning. With a single tagged release and no UPGRADE.md, pin to 1.0.* and read the diff on every bump. Budget a re-read of the migrations folder each time.
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.
htinlynn/genius-helper
maco-studios/hephaestus
elmogy/larafast
xeviant/laravel-paystack
gorilladash/laravel-website-sdk
martialbe/flysystem-oss
chondal/3312client
jeroen-g/flickr
opscale-co/nova-genbi
itsjustvita/laravel-retention
tequilarapido/trackit
gregsphotography/site-builder-filament
cabaoctavio/laravel-query-log
gregsphotography/site-builder-components
io-digital/clickatell
snowsoft/laravel-admin
oxygen/auth
relicsoftware/barakah-payment-gateway
tobya/work-with-composer
equipc/laravel-email-validator