webchemistry/invoice
PHP invoice library for generating invoices with PDF output, QR payment codes, and configurable invoice data. Simplifies creating, rendering, and exporting invoices in PHP applications.
Architecture fit. webchemistry/invoice is a standalone PHP library, not a Laravel package. It ships no service provider, no publishable config, no facade, and no Laravel version constraints. Its natural home is the Nette ecosystem (the vendor is a Czech Nette-oriented agency), and it typically couples a domain model of invoices/items/VAT with a PDF renderer and a template layer. In a Laravel codebase it must be treated as an infrastructure adapter behind a first-party interface — e.g. an InvoiceRenderer contract bound in AppServiceProvider — never called directly from controllers or models. The invoice domain objects are the reusable value here; the rendering and templating layers are the parts most likely to fight our conventions.
Integration feasibility. Composer-installable and MIT-licensed, so legal friction is near zero. The real work is containment: we would build a thin adapter that maps our own Invoice aggregate into the package's structures, owns template selection and branding assets, and returns a streamed/stored PDF. If the package renders via Latte templates, we either accept Latte as an invoice-only templating island (documented exception) or bypass its view layer and use only its data model. Both are viable; the first is faster, the second is cleaner long-term.
Technical risk. The dominant risk is vendor concentration: ~98 stars, a single agency maintainer, no listed repository URL in our metadata, and an unknown bus factor. The release history shows activity (2026-02-10) but we cannot audit commit cadence, issue responsiveness, or test coverage from what we have. Secondary risks: a heavyweight PDF engine (mPDF-family renderers are memory-hungry and slow relative to headless-Chrome approaches), UTF-8/font embedding pitfalls, and a Czech/EU-centric VAT and currency model that may not express reverse-charge, OSS, or multi-jurisdiction rules. Finally, the low opportunity score (1.2) is a signal in itself — this is a commoditized problem with strong alternatives (spatie/laravel-pdf, dompdf, hosted services like Stripe Invoicing or Invoice Ninja), so differentiation must come from compliance fit, not the library.
Key questions. Which PDF backend and template engine does it actually depend on, and at what versions? Can templates and layouts be fully overridden without forking? Does it model tax regimes beyond Czech/EU standard VAT — reverse charge, zero-rate with note, multi-currency rounding? How are invoice number sequences allocated (atomic, gap-free, per-entity)? Is the package tested against PHP 8.2–8.4 and does it declare Laravel-compatible constraints? Is the source repository publicly auditable for supply-chain review? What is the realistic memory ceiling per render?
Stack fit. Composer-native and PHP-version tolerant in principle, but expect dependency contention around the PDF engine and template library. We should install it in isolation first and run composer why-not checks against our locked dependency graph. Our stack (Laravel queues, Flysystem disks, Blade, signed URLs) provides everything needed around it — the package only needs to produce bytes.
Migration path. Introduce behind an interface with two implementations: the existing generator and the new one. Run a parallel-render period where both produce PDFs for the same invoice payloads, compared by golden-file tests on text extraction and layout snapshots. Cut over per invoice type (e.g. standard domestic first, credit notes and cross-border later) rather than big-bang.
Compatibility. Pin exact versions — no caret ranges — given the maintenance profile. Verify PHP matrix, ext-gd/ext-mbstring availability in our runtime image, and font assets baked into the container. Storage must route through Laravel disks so retention and access-policy stay consistent with our existing document handling.
Sequencing. (1) Timeboxed spike: render one real invoice end-to-end, measure memory and latency. (2) Domain adapter + contract + config + feature flag. (3) Branding/template work with design sign-off. (4) Move rendering to queued jobs with storage and signed-URL delivery. (5) Parallel run and reconciliation. (6) Decommission the legacy path. Roughly 1–2 dev-days for the spike and adapter, 1–2 weeks to productionize including compliance review.
Maintenance. We own the integration layer outright; the package is a pinned dependency we may need to fork. Budget for periodic audits of upstream releases and a documented fork procedure. Track it in the same inventory as other single-maintainer dependencies so it surfaces in supply-chain reviews.
Support. No commercial support channel; GitHub issues only, with unknown latency. Internal ownership must be explicit — a named team accountable for templates, fonts, and compliance correctness.
Scaling. PDF rendering is CPU- and memory-bound. Keep it off the request path: dedicated queue, bounded worker concurrency, per-job memory limits, and timeouts that fail fast rather than OOM the node. Cache fonts and static assets in the image. At volume, consider a separate render service if invoice generation competes with customer-facing traffic.
Failure modes. Missing or unembedded fonts producing garbled or blank glyphs; memory exhaustion under concurrent renders surfacing as 500s or silent job loss; rounding and currency errors that are legally material rather than cosmetic; invoice-number collisions if sequence allocation is not atomic under concurrency; storage write failures leaving paid orders without documents; and silent layout breakage on template or dependency upgrades. Each needs a detection hook — text-extraction assertions, sequence-integrity checks, and alerting on render failures.
Ramp-up. Low to consume the API; medium to customize templates if they are Latte-based and the team is Blade-fluent; medium-to-high for the compliance and legal review, which is the true critical path. Plan for one engineer to hold deep knowledge, with a second trained on the template layer to avoid a single-person dependency mirroring the upstream one.
How can I help you explore Laravel packages today?