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

Erp Laravel Package

amplify/erp

amplify/erp is a Laravel package for building modular ERP applications, offering a foundation for core enterprise resource and workflow concerns so teams can integrate and extend business functionality within existing Laravel projects.

View on GitHub
Deep Wiki
Context7

Getting Started

This is an unproven package (0 stars, 0 dependents, single release dated in the future), so treat the first hour as reconnaissance rather than a normal composer require. The description — "CSD, Fact Module Adapter module" — points at Mexican electronic invoicing (CSD = Certificado de Sello Digital, the SAT-issued sealing certificate) wrapped in a pluggable "fact module adapter". Plan accordingly: you are integrating a stamping adapter, not a generic ERP.

composer require amplify/erp
php artisan vendor:publish --provider="Amplify\Erp\ErpServiceProvider"   # verify the real FQCN first
php artisan migrate

Minimal setup checklist before writing any code:

  1. Verify the package exists and is installable. composer show amplify/erp --all and check the tag list. With one release and a 2026 date, confirm the tag actually resolves and that composer.lock pins a commit hash, not just ^1.0.
  2. Read src/ before reading config. Look for the module service provider and any *Adapter, *Driver, *Contract, or *Interface classes. The word "Adapter" in the description strongly implies an abstract contract with at least one concrete driver — that contract is your integration surface.
  3. Publish and diff config. config/erp.php (or similarly named) will tell you more than any README: driver selection, credential paths, environment/DNS keys, sandbox flags, storage disks.
  4. Check migrations and model namespaces. Zero dependents means namespace and table-prefix collisions are plausible. Inspect table names before running migrate in a database with existing invoicing tables.
  5. Find the routes/controllers, if any. If the package ships HTTP endpoints for stamping or webhooks, you'll want to know immediately; if it's service-layer-only, you'll be calling it from your own controllers and jobs.

First use case to attempt: issue and stamp one invoice against the sandbox/test environment of the underlying PAC (the stamping provider), using a throwaway CSD test certificate. That single round-trip exercises config loading, credential resolution, the adapter binding, the XML/CFDI payload, the persistence layer, and error handling — the five places this kind of module usually breaks. Do not attempt production stamping until you have a stored UUID and a retrievable XML in hand.

Implementation Patterns

Bind through the contract, not the concrete class. The package almost certainly exposes an interface for the "fact module" and resolves a driver from config. Inject the interface everywhere in your application code, and let config choose the implementation. This is what insulates you from the package being abandoned:

// config/erp.php
'driver' => env('ERP_DRIVER', 'csd'),
'sandbox' => env('ERP_SANDBOX', true),

// your code
public function __construct(private \Amplify\Erp\Contracts\FactAdapter $fact) {}

Treat stamping as an async, idempotent operation. Stamping is a network call to a PAC, it can time out after the invoice was accepted, and retries without an idempotency key will produce duplicate CFDI. Queue the job, record your own invoice_request_id before the call, and reconcile on retry by querying the package's status/lookup method rather than blindly re-submitting.

final class StampInvoice implements ShouldQueue
{
    public function __construct(public int $invoiceId) {}

    public function handle(FactAdapter $fact): void
    {
        $invoice = Invoice::findOrFail($this->invoiceId);
        if ($invoice->uuid) return; // already stamped

        $result = $fact->stamp($invoice->toFactPayload());
        $invoice->update([
            'uuid'    => $result->uuid,
            'status'  => $result->status,
            'xml'     => $result->xml,   // persist raw; PACs lose things
        ]);
    }
}

Wrap the package in a thin application-level service. One class — InvoiceStamper or similar — is the only thing that touches the package's API. You get a single place to add logging, metrics, retries, and a single place to swap in a fork or a direct PAC SDK later. Given the maintenance signals here, assume you may need to fork.

Multi-tenant / multi-company credentials. ERP integrations are rarely single-tenant: each legal entity has its own RFC and its own CSD. Do not rely on a single global config value for the certificate path. Resolve credentials per company — via a table, a disk path convention, or a scoped container binding — and check whether the package's adapter supports a per-call credential override before you build around it. If it only reads config, you'll need one config namespace per tenant or a decorator that temporarily rebinds config.

Store the artifacts you'd hate to regenerate. Persist the stamped XML, the PDF, the UUID, the PAC's response payload, and the timestamp. Never rely on the package (or the PAC) to hand them back later — most do, for a fee or a retention window, and none do reliably in sandbox.

Test with fixtures, not the sandbox. Capture one good and two or three failing PAC responses (certificate expired, malformed RFC, duplicate UUID) as JSON/XML fixtures, bind a fake implementation of the adapter contract in your test suite, and assert on your own persistence and job behavior. Integration-test against the sandbox separately and sparingly.

Gotchas and Tips

  • The maintenance signal is the headline risk. Zero stars, zero dependents, one release. Pin an exact version or a commit ref, commit composer.lock, and budget for the possibility that you maintain a fork. If you can't read the source and understand the stamping path end to end in an afternoon, don't put it in the critical path of your billing.
  • Verify the release date. A publication date in the future usually means a force-pushed tag, a misconfigured CI, or a republished package. Confirm the tag's commit matches what you installed.
  • CSD certificate handling is the #1 operational failure. Certificates expire (typically ~4 years, but check), .cer/.key are DER-encoded binary and not PEM — most libraries want raw DER plus the password in the exact expected encoding. Passwords go in .env and out of config caching, and file paths must be readable by the PHP-FPM user. Set up an expiry alert the day you go live.
  • Config caching and secrets. php artisan config:cache will freeze the driver and sandbox flag. If credentials are read at boot into a singleton, rotating a certificate means config:clear + a deploy. Prefer resolving credentials lazily per invoice.
  • Timezone, currency, and locale. CFDI dates must be in the correct local/SAT timezone, and Carbon::now() in a UTC container will silently produce wrong Fecha. Set the app timezone deliberately and don't let the package default it.
  • Duplicate stamping is expensive and hard to unwind. A UUID is consumed once issued. Build the idempotency guard described above before your first retry storm, not after.
  • Table and namespace collisions. Run php artisan migrate --pretend first. If the package uses generic table names (invoices, documents), you will collide with existing schema. Some modules let you override table names via config; many don't.
  • Extension points to look for, in priority order: (1) the adapter/driver contract — implement your own to bypass the package entirely while keeping its models; (2) events around stamping success/failure — hook your own notifications, accounting sync, and dunning off them; (3) config-driven driver and disk selection; (4) model $fillable/$casts and any repository layer. If none of these exist, keep your integration shallow.
  • Debugging stamping failures: the PAC's error is usually nested in an XML response body returned with an HTTP 200. Log the full raw response, not just the exception message. Look for a package-level "last response" accessor or a debug/verbose config flag before reaching for a network sniffer.
  • Watch for missing authorization. If the package registers routes, check their middleware. Third-party modules frequently ship routes without auth/tenant scoping; wrap or disable them in RouteServiceProvider if you find them exposed.
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.
diephp/sequences
users-au/socialite-provider
twidpay/twid-logger
mrnewport/laravel-plaid
mrnewport/laravel-repo
mrnewport/laravel-docsign
mrnewport/laravel-stow
mrnewport/laravel-flow
mrnewport/laravel-priceable
mrnewport/laravel-nestedterms
fredmeng/laravel-apidoc-generator
itstructure/laravel-multilingual-tools
pdustdar/elasticsearch
markupai/php-sdk
rlacerda83/lumem-microservice-shipment
uni-method/symfony-lib
tacticmedia/scim-server-bundle
neika-ai/symfony-bundle
mattleads/agent-publishing-bundle
glavweb/framework-bundle