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

Pos Bundle Laravel Package

mews/pos-bundle

mews/pos-bundle is a PHP package for integrating Mews POS into your application. It provides bundle configuration and service wiring to connect point-of-sale workflows, sync POS data, and support hospitality property integrations with less boilerplate. Suitable for Symfony projects needing Mews POS...

View on GitHub
Deep Wiki
Context7

Getting Started

This is mews/pos v2 — the Turkish virtual-POS abstraction layer (Asseco/Est, PosNet, KuveytTürk, VakıfKatılım, PayFlex, Iyzico, PayTR, Param). v2.0.0 is a rebuild-level major: namespaces moved, gateways were renamed, and the config schema was restructured. If you are onboarding fresh, you are on the good path — there is no legacy baggage to unlearn. If you are upgrading, read docs/UPGRADE-2.0.md before touching code, then follow the order below.

Prerequisites

  • PHP >= 8.0 (7.4 is no longer supported)
  • Symfony components >= 5.4
  • mews/pos ^2.0

Minimal steps

  1. Install and publish the config:
    composer require mews/pos:^2.0
    php artisan vendor:publish --tag=pos-config
    
  2. Check your runtime first — most upgrade failures are environmental:
    php -v                     # must be 8.0+
    composer show mews/pos     # must be 2.x, not 1.x
    
  3. Migrate the config file to the v2 shape. The three renames that break silent-at-runtime:
    • credentials.enc_key → credentials.secret_key
    • bank-level test_mode → gateway_configs.test_mode
    • bank-level lang → gateway_configs.lang
    • delete credentials.payment_model and gateway_endpoints.payment_api_2
  4. Update imports: Mews\Pos\Gateways\* → Mews\Pos\Gateway\*, and rename EstPos/EstV3Pos → AssecoPos, PosNet → PosNetPos.
  5. Run one sandbox 3D payment end-to-end before writing any feature code.

First use case: a single Asseco 3D Secure payment in test mode. This exercises the whole surface — account model, gateway config, 3D form generation, callback handling — and will surface every config mistake at once instead of one at a time.

use Mews\Pos\Gateway\AssecoPos;
use Mews\Pos\Model\Account\AssecoPosAccount; // exact class names: see docs/UPGRADE-2.0.md

$account = new AssecoPosAccount([
    'bank'       => 'akbank',
    'merchant_id'=> config('pos.banks.akbank.credentials.merchant_id'),
    'username'   => config('pos.banks.akbank.credentials.username'),
    'password'   => config('pos.banks.akbank.credentials.password'),
    'secret_key' => config('pos.banks.akbank.credentials.secret_key'), // was enc_key
    'lang'       => 'tr',
]);

Where to look first: docs/UPGRADE-2.0.md for the mapping table, then the gateway_configs block in the published config — it is the single source of truth in v2.

Implementation Patterns

Treat gateway_configs as the new centre of gravity. v2 pushed per-gateway behaviour out of the bank block and into gateway_configs.{bank}.{gateway}. lang and test_mode now live there and are honoured by all gateways, which is a genuine improvement — you can flip a single bank to test mode without touching its credentials. Model this in your own app config as a merged array rather than duplicating bank blocks:

// config/pos.php
'gateway_configs' => [
    'akbank' => [
        'test_mode' => env('POS_TEST_MODE', true),
        'lang'      => 'tr',
    ],
],

Wrap gateway construction in a resolver, not in controllers. Gateway class names changed in this release and will change again. One binding, one place to fix:

// app/Services/Payment/GatewayResolver.php
public function make(string $bank): PosInterface
{
    $config  = config("pos.banks.{$bank}");
    $account = $this->accountFactory($bank, $config); // your own factory
    return PosFactory::create($config, $account, $this->gatewayClass($bank));
}

Note the package's own bundle AccountFactory was deleted in v2 — if you relied on it, this resolver is the replacement. Keep the account-construction switch here too.

Persist payment attempts before redirecting to 3D. The classic pattern: create a local Payment row with a generated order_id and status pending, call prepare() + get the 3D form data, render the auto-submitting form. On callback, look the row up by order_id, call the gateway's status/provision query, and only then mark it paid. Never trust the callback's success flag alone — always confirm server-side.

Choose the right 3D variant per gateway, not globally. v2 removed payment_api_2 and split Param 3D Host payments into a dedicated Param3DHostPos gateway. The rule of thumb:

  • Standard 3D Secure (browser redirect with bank-hosted page) → the bank's normal gateway.
  • 3D Host / "Param 3D Host" style flows where the card entry page is hosted separately → Param3DHostPos, distinct account and config.
  • Non-3D / MoTo → same gateway, different payment model argument.

Use a strategy layer for the new gateways. IyzicoPos and PayTrPos have materially different request/response semantics from the bank gateways (wallet-style redirects, different callback payloads). Rather than if ($bank === 'iyzico') sprinkled through controllers, define a small PaymentGatewayDriver interface in your app with initiate(), handleCallback(), refund() and let each package gateway sit behind one implementation. This is what makes swapping a bank a one-file change.

Test mode belongs in gateway_configs, and test it explicitly. Write a feature test that asserts the generated 3D form action URL points at the sandbox host — that single assertion catches almost every test_mode misconfiguration, including the v1 leftover of putting test_mode at bank level where v2 now ignores it.

Integration tip — queue the reconciliation. Bank status endpoints are slow and occasionally flaky. On callback, respond 200 fast, dispatch a job that queries the gateway and updates the order. Use retry() with backoff and an idempotency guard on order_id, because banks retry callbacks.

Gotchas and Tips

The silent failures are the config ones. payment_model, bank-level test_mode, and bank-level lang were removed, not deprecated. A leftover test_mode => false at bank level will not raise an error — it will just be ignored, and your sandbox traffic hits production. Grep your config for enc_key, payment_model, test_mode, and payment_api_2 and confirm zero hits outside gateway_configs.

enc_key → secret_key is the sneakiest rename. It is inside credentials, so a config('pos.banks.x.credentials.enc_key') call returns null and the gateway fails with a hash/signature error that looks like a bank-side problem. If you see "invalid hash" or "MAC verification failed" after upgrading, check this key first.

Namespace moves break string-based resolution. Mews\Pos\Gateways\* → Mews\Pos\Gateway\* (singular). If you resolve gateway classes via config strings, class_exists checks, or a DI container alias, those strings need updating too — PHP will not warn you until instantiation. Same for PayForAccount → PayForPosAccount (now under Mews\Pos\Model\Account, not Entity\Account).

gateway_3d is now optional for KuveytPos / VakifKatilimPos / PayFlexCPV4Pos. v2 derives it from payment_api. Remove the explicit key or you will be maintaining a value that is ignored — and if you had a wrong value there, v1 hid it and v2 fixes it, which can change behaviour on upgrade. Re-run a 3D payment for those three banks specifically.

Test mode is per-gateway now, not per-bank. In multi-gateway setups (e.g. a bank with both a standard and a 3D-host gateway) you can end up half in sandbox. Assert the endpoint host in tests, or log the resolved endpoint at boot in non-production.

Debugging order when a payment fails: (1) dump the fully merged config after gateway_configs resolution; (2) confirm secret_key and merchant_id are populated, not null; (3) confirm test_mode resolves correctly; (4) only then log the raw gateway request/response. Banking APIs return generic error codes — the package's response object carries the bank's raw message, which is usually the only thing that tells you the truth.

Extension points: the package's own AccountFactory is gone, so subclassing/extending account creation is now entirely your code — that is the intended extension seam. For gateway behaviour tweaks, prefer wrapping the package gateway behind your own driver interface over subclassing the concrete Gateway\* classes; the class names already moved once in this release and are not a stable extension point.

Pin the version and read release notes before composer update. This release changed namespaces, config keys, and class names simultaneously. Add "mews/pos": "2.0.*" at minimum, and keep docs/UPGRADE-2.0.md linked from your README so the next major is a checklist rather than an archaeology project.

Framework version coupling: dropping Symfony 4 and PHP 7.4 is good hygiene but check your CI matrix and any Docker base images — a Laravel app still on PHP 7.4 cannot install this at all, and the composer error is a confusing dependency conflict rather than a clear version message.

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.
shitoudev/permissionmanager
johannesclimacus/laravel-tui
hocvt/seotools
vitalybaev/sypexgeo
amphibee/themosis-ignition
gito-me/fast-excel
frankyso/laravel-ipaymu
geolize-studio/laravel-chile
boomerangui/chat
jinas/dhivatar
store-doc/laravel-storage-driver
plus-it/laravel-translation-manager
diephp/perhaps
diephp/telegraph
osmaviation/spreadsheet
microsoft/fluentui-system-icons
mmccook/php-json-canonicalization-scheme
middlewares/firewall
qubiqx/montapacking
nyoncode/laravel-package-console