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

Finkok Bundle Laravel Package

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.

View on GitHub
Deep Wiki
Context7

Getting Started

  • Install with 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.
  • Requirements: PHP ^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).
  • First integration step is not config YAML: implement and register a CredentialsProviderInterface service returning multi-emisor profiles (RFC, environment DEMO/PROD, optional cer/key/passwords). The bundle deliberately reads no credentials from its own configuration.
  • Look first at the README, then docs/errores.md (full stamping/cancellation code catalogs, CSD encoding process, DEMO behavior).
  • First use case: call 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.

Implementation Patterns

  • Per-tenant credential provider. Resolve the profile from the active tenant/DB/secret manager inside CredentialsProviderInterface. This is the intended pattern for multi-RFC apps; there is no finkok.profiles config to fall back on.
  • Preview, then stamp. Use 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.
  • Inspect DTOs, don't parse payloads. Business errors (300, 307, 705…) are returned, not thrown. Check 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.
  • Cancellation is a workflow, not a call. 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.
  • Use 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.
  • Omit 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.
  • Let retries stay internal. Transport errors and transient codes (205, 302, 708, 798) are retried safely because Finkok deduplicates by UUID. Keep your own queue/job retries idempotent and keyed by UUID rather than adding a second retry layer around non-transient codes.
  • Testing: inject 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.
  • Wrap it. Expose your own application service around stamp/cancel that persists the DTO result and UUID, so controllers and jobs stay thin and you can swap profiles cleanly.

Gotchas and Tips

  • Breaking changes if you came from 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().
  • 1 MB per XML. Exceeding it can affect stamping of subsequent comprobantes, not just the current one — validate size early.
  • Hard SAT/Finkok limits: 72 hours to stamp, and up to 72 hours for SAT to reflect a newly issued certificate in the taxpayer list. Maximum 5 cancellation attempts per UUID; the 6th returns 799 and can only be finished in the SAT portal.
  • DEMO has its own timings: 1–5 min wait after stamping before cancelling, 30 min to reach "cancelable con aceptación", and auto-resolution of acceptance at 5 min. Tests and demos that assume real-time cancellation will look broken.
  • Multi-emisor leakage risk. Since the bundle reads no credentials itself, a wrong CredentialsProviderInterface result silently stamps with the wrong RFC. Assert the profile RFC matches the XML emisor before sending.
  • No \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.
  • Response parsing is by local name (prefix-agnostic), but request envelopes still need their exact namespaces — never hand-modify them; regenerate via preview.
  • CSD encoding is done for you (PEM with key password, DES3 with panel password, base64 exactly once, cert with headers). Double-encoding or pre-encoding is the classic failure; prefer omitting the CSD entirely.
  • Don't blanket-retry business codes. Only transport failures and 205/302/708/798 are retried; retrying 300/301/307/603/705/799 wastes attempts (and for cancellation, burns your 5-try budget).
  • 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.
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