estratos/finkok-bundle
Laravel package integrating Finkok's CFDI web services for Mexican e-invoicing. It simplifies stamping, cancellation, and invoice management with configurable clients, clean service wrappers, reusable components, and straightforward configuration for reliable SAT-compliant workflows.
composer require estratos/finkok-bundle. This is a Symfony 7.4 bundle, not a Laravel package: register Estratos\FinkokBundle\FinkokBundle::class => ['all' => true] in config/bundles.php. In a Laravel app, budget glue code for the Symfony DI wiring (or reuse the underlying HTTP/DTO layer directly); the transport, DTOs and error catalogs are the valuable, portable parts.^8.2, dom + libxml (and openssl only if you cancel with your own CSD). ext-soap is not required — the SOAP envelopes are hand-built and sent via Symfony HttpClient, which is the main reason to pick this over a \SoapClient wrapper (works on hosts where SOAP is disabled, and is testable byte-for-byte).CredentialsProviderInterface service returning multi-emisor profiles (RFC, environment DEMO/PROD, optional cer/key/passwords). The bundle deliberately reads no credentials from its own configuration.docs/errores.md (full stamping/cancellation code catalogs, CSD encoding process, DEMO behavior).previewStampRequest() to inspect the generated envelope without opening a connection, then stamp() against DEMO and inspect the returned DTO with isSuccess() / getIncidences(). This gets you to a working stamp with zero risk of burning timbrados.CredentialsProviderInterface. This is the intended pattern for multi-RFC apps; there is no finkok.profiles config to fall back on.previewStampRequest() and the built-in XML pre-validation (empty, malformed, no seal, not a CFDI, >1 MB) before spending a timbrado. Treat local validation failures as a separate, non-retryable path.isSuccess(), getIncidences(), hasErrorCode(); use assertSuccess() in places where a business error should blow up (e.g. a synchronous admin action), and return the DTO where it shouldn't.cancel() returning 201 only means the petition was sent — poll get_sat_status() and branch on isRequestAccepted() / isCancelled() / isInProcess(). Drive this from a scheduled job, not inline in a request.getStatusOf($uuid, $rfc, $total) for cancellation status when you have the CFDI XML: it reads the three values for you and sidesteps the 601 mismatch error.cer/key when you don't have a CSD. The bundle skips them and Finkok uses the panel certificate; this is the low-risk default. Only send them if your flow requires it.MockHttpClient and fixtures of real responses (the release ships 219 offline tests as a model). Keep the --group live contract tests out of the default CI run.stamp/cancel that persists the DTO result and UUID, so controllers and jobs stay thin and you can swap profiles cleanly.dev-main: namespace moved from Finkok\CfdiBundle to Estratos\FinkokBundle, and finkok.profiles / finkok.default_profile no longer exist. No stable consumers affected, but pin and grep for old namespace references.201 is not a cancellation. Never mark a CFDI cancelled from the cancel() response alone; always confirm via get_sat_status().799 and can only be finished in the SAT portal.CredentialsProviderInterface result silently stamps with the wrong RFC. Assert the profile RFC matches the XML emisor before sending.\SoapClient to debug with. When something fails, dump the raw request/response bodies — the whole point is that they are auditable byte-for-byte; use previewStampRequest() for envelope inspection instead of hand-editing XML.assertSuccess() in queue jobs is a policy decision — Finkok can stamp successfully and still return incidences, so decide per code whether it's a failure.How can I help you explore Laravel packages today?