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

Efatura Laravel Package

furkankadioglu/efatura

Laravel package for Turkish e-Fatura integration. Create, sign, and send UBL-TR electronic invoices to the GİB portal through a simple, fluent API, with easy configuration and XML output for PHP applications.

View on GitHub
Deep Wiki
Context7

Getting Started

  • Install with composer require <vendor>/<package> and publish the config: php artisan vendor:publish --tag=<package>-config. The published config file is the first thing to read — it holds credentials, endpoint/URL selection, and the test_mode / test-account switches that 1.9.4 touched.
  • Add the credentials to config/services.php (or the package config) and to .env, never hard-coded. Resolve them via config() so php artisan config:cache works in production.
  • Check the service provider for what is bound into the container (a client/manager class and usually a Facade). Prefer constructor-injecting the contract/interface over the facade so the code stays testable.
  • First use case: run one complete payment with SMS confirmation end-to-end in the sandbox — create the payment, receive the provider's callback to your return URL, confirm, then query the resulting invoice. Do this once manually before writing any application code around it; the callback shape is the part that dictates your design.
  • Second use case: the new invoice query (adımıza düzenlenen faturalar). Wire it into a php artisan tinker session or a one-off command first — it is read-only, so it is the safest way to validate credentials and endpoint configuration before touching money flows.

Implementation Patterns

Wrap the package, don't sprinkle it. Create a small application-level service (App\Services\Payments\Gateway) that takes the package client in its constructor and exposes your domain verbs: startPayment(), confirm(), invoicesForPeriod(). When the package inevitably changes its method signatures, you patch one class instead of forty controllers.

SMS confirmation callback flow

  • Register the callback route outside the web middleware group (or explicitly withoutMiddleware(VerifyCsrfToken::class)). Providers POST cross-origin with no session and no CSRF token.
  • Do not trust the payload. Validate the hash/signature field before anything else, then re-query the transaction status from the provider rather than trusting status=success in the POST body.
  • Make the handler idempotent: providers retry. Use the provider's transaction/order reference as a unique key (a unique index plus firstOrCreate, or a cache lock) so a duplicate callback does not double-fulfil an order.
  • Keep the handler fast — persist the raw payload, dispatch a queued job, return the exact response body the provider expects (OK or similar). A slow handler that times out triggers retries.

Test account override (new in 1.9.4)

  • Drive it from config, not code: config('gateway.test_account') sourced from an env var. That way staging uses the manual test account and production simply has the value unset.
  • Resolve it through a single accessor (a small TestAccountResolver) rather than passing it around, so you can log centrally which mode is active.
  • Consider a boot-time guard in AppServiceProvider::boot() that throws in production if a test account is configured. This is the single highest-value line of code around this feature.

Invoice querying

  • Model the response as DTOs (App\Data\InvoiceData) and map to your own Eloquent model if you need history. Never let package response objects leak into Blade views or API resources.
  • Query on a schedule: a daily InvoiceSync command that pages backwards from today, upserts by invoice number/ETTN, and stores the PDF URL. Cache aggressively — invoice data is immutable once issued.
  • For on-demand lookups (a customer portal), cache per-invoice for a day and use Cache::remember keyed on the invoice identifier, not on the date range.

Testing

  • Use Http::fake() with recorded fixtures from the real sandbox. Record the SMS-confirmation callback body as a fixture too and assert your handler is idempotent by replaying it twice.
  • Feature-test the callback route with $this->post(...) and assert the exact response body — providers are strict about it.

Gotchas and Tips

  • config:cache bites on deploy. Changing the test-account env var does nothing until the config is re-cached. If "it's still using the test account in production" gets reported, that is the first thing to check.
  • Amounts. Turkish gateways typically want amounts as integer minor units or as a "123,45"-style decimal string depending on endpoint — check the package's expectation per call; mixing them silently charges 100×. Store money as integers in your DB and convert only at the boundary.
  • Callback URL reachability. Local dev cannot receive the POST. Use a tunnel and set the callback URL from config, not from a hard-coded route helper, so staging and prod differ only by env.
  • Timezone and date ranges. Invoice queries are usually in local time (Europe/Istanbul) while your app may be UTC. An off-by-one at month boundaries shows up as a missing invoice, not an error.
  • Rate limits on invoice queries. Bulk backfilling months of invoices in a tight loop will get you throttled. Chunk by day, add usleep/RateLimiter, and make the job resumable via a checkpoint column.
  • Debugging. Enable the package's HTTP logger (usually a config flag) only in non-production, and log the raw request/response pair to a dedicated channel — the provider's error messages are often more informative than the exception the package throws. Wrap calls in try/catch and translate to your own exception type so you can distinguish "credentials wrong" from "card declined".
  • Silent test-mode leakage. After adding the 1.9.4 manual test account, double-check that the flag lives in a config branch that cannot be set from a request parameter. If the package exposes it as a per-call argument, never pass it from user input.
  • Extension points. Before forking, check for events dispatched around the confirmation callback, a Macroable trait, or an overridable HTTP client binding — most of what you'd want to change (headers, retries, logging) is usually reachable by rebinding one class in your own service provider.
  • Pin the version. This is a minor release with behavioural fixes to a payment-critical path; run the full test suite against fixtures from the sandbox after upgrading, and watch the SMS-confirmation flow specifically since it was the thing changed.
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.
ignibyte/aic-framework
glavweb/data-schema-bundle
glavweb/datagrid-bundle
tacticmedia/scim-server
uni-method/frame
neika-ai/sdk
adachsoft/php-code-style
pharaonic/laravel-notification-dependencies
beautinow/translug
dev-brainiac/bot-cloaked
octoberrain/html
octoberrain/extension
octoberrain/exception
octoberrain/contracts
frankyso/ipaymu
3mdikram/worldmoneywords
snowsoft/config
itmosoft/laravel-subscriptions
larva/laravel-ai-qwen
adachsoft/api-version-bundle