mews / laravel-pos
Laravel 11 POS 包
1.0.1
2024-09-09 13:00 UTC
Requires
- php: >=7.4
- illuminate/config: ^8.0|^9.0|^10.0|^11.0
- illuminate/support: ^8.0|^9.0|^10.0|^11.0
- mews/pos: ^1.3
Requires (Dev)
- orchestra/testbench: ^8.17|^9.0|^10.0|^11.0
README
基本包
主要标题
最低要求
- PHP >= 7.4
- mews/pos ^1.3
- laravel 8, 9, 10, 11
安装
-
$ composer require mews/laravel-pos $ php artisan vendor:publish --tag=laravel-pos
-
/config/laravel-pos.php
根据您手中的网关信息更新您的设置。示例配置<?php # /config/laravel-pos.php return [ 'banks' => [ 'kuveytpos' => [ # ilk sıradaki banka injection için default olur. 'gateway_class' => \Mews\Pos\Gateways\KuveytPos::class, 'test_mode' => true, 'lang' => \Mews\Pos\PosInterface::LANG_TR, 'credentials' => [ 'payment_model' => \Mews\Pos\PosInterface::MODEL_3D_SECURE, 'merchant_id' => 'xxx', 'terminal_id' => 'yyyyyyy', 'user_name' => 'zzzzzzz', 'enc_key' => 'www123', ], 'gateway_endpoints' => [ 'payment_api' => 'https://boatest.kuveytturk.com.tr/boa.virtualpos.services/Home', 'gateway_3d' => 'https://boatest.kuveytturk.com.tr/boa.virtualpos.services/Home/ThreeDModelPayGate', 'query_api' => 'https://boatest.kuveytturk.com.tr/BOA.Integration.WCFService/BOA.Integration.VirtualPos/VirtualPosService.svc?wsdl', ], ], 'estpos_payten' => [ 'gateway_class' => \Mews\Pos\Gateways\EstV3Pos::class, 'test_mode' => true, 'lang' => \Mews\Pos\PosInterface::LANG_TR, 'credentials' => [ 'payment_model' => \Mews\Pos\PosInterface::MODEL_3D_SECURE, 'merchant_id' => '7001132146464', 'user_name' => 'ISBXXXXX', 'user_password' => 'ISBYYYYY', 'enc_key' => 'TRPZZZZZ', ], 'gateway_endpoints' => [ 'payment_api' => 'https://entegrasyon.asseco-see.com.tr/fim/api', 'gateway_3d' => 'https://entegrasyon.asseco-see.com.tr/fim/est3Dgate', 'gateway_3d_host' => 'https://sanalpos.sanalakpos.com.tr/fim/est3Dgate', ], ], ], ];
-
如果您使用PHP Session,则必须按照以下方式配置session以进行3D支付。
Laravel 11 的环境变量如下
SESSION_SECURE_COOKIE=true SESSION_SAME_SITE=None
Laravel 10, 9, 8 则需要在环境变量中设置
SESSION_SECURE_COOKIE=true
并在/config/session.php
中更新same_site
值# /config/session.php: return [ // ... 'same_site' => 'none', ]
更改后,请删除现有的session并创建新的session。
-
在3D支付中,银行将重定向到网站上的URL(成功/失败URL)时,需要关闭CSRF。
Laravel 11 可以使用
withMiddleware()
方法进行设置。<?php # /bootstrap/app.php use Illuminate\Foundation\Application; use Illuminate\Foundation\Configuration\Exceptions; use Illuminate\Foundation\Configuration\Middleware; return Application::configure(basePath: dirname(__DIR__)) // ... ->withMiddleware(function (Middleware $middleware) { $middleware->validateCsrfTokens(except: [ '/single-bank/payment/3d/response' ]); });
Laravel 10, 9, 8 可以在
/app/Http/Middleware/VerifyCsrfToken.php
中进行设置。<?php # /app/Http/Middleware/VerifyCsrfToken.php namespace App\Http\Middleware; use Illuminate\Foundation\Http\Middleware\VerifyCsrfToken as Middleware; class VerifyCsrfToken extends Middleware { protected $except = [ // success ve fail URL'lar buraya eklenecek: '/single-bank/payment/3d/response', ]; }
-
KuveytPos 对于API请求需要添加额外字段,可以使用事件监听器来做到这一点。示例
<?php # /app/Listeners/KuveytPosV2RequestDataPreparedEventListener.php: namespace App\Listeners; use Mews\Pos\Event\RequestDataPreparedEvent; /** * KuveytPos TDV2.0.0 odemenin calismasi icin zorunlu eklenmesi gereken alan var. */ class KuveytPosV2RequestDataPreparedEventListener { public function __invoke(RequestDataPreparedEvent $event): void { if ($event->getGatewayClass() !== \Mews\Pos\Gateways\KuveytPos::class) { return; } /** * ekstra eklenmesi gereken verileri isteseniz $order icine ekleyip sonra o verilere * $event->getOrder() ile erisebilirsiniz. */ $additionalRequestDataForKuveyt = [ 'DeviceData' => [ /** * DeviceChannel : DeviceData alanı içerisinde gönderilmesi beklenen işlemin yapıldığı cihaz bilgisi. * 2 karakter olmalıdır. 01-Mobil, 02-Web Browser için kullanılmalıdır. */ 'DeviceChannel' => '02', ], 'CardHolderData' => [ /** * BillAddrCity: Kullanılan kart ile ilişkili kart hamilinin fatura adres şehri. * Maksimum 50 karakter uzunluğunda olmalıdır. */ 'BillAddrCity' => 'İstanbul', /** * BillAddrCountry Kullanılan kart ile ilişkili kart hamilinin fatura adresindeki ülke kodu. * Maksimum 3 karakter uzunluğunda olmalıdır. * ISO 3166-1 sayısal üç haneli ülke kodu standardı kullanılmalıdır. */ 'BillAddrCountry' => '792', /** * BillAddrLine1: Kullanılan kart ile ilişkili kart hamilinin teslimat adresinde yer alan sokak vb. bilgileri içeren açık adresi. * Maksimum 150 karakter uzunluğunda olmalıdır. */ 'BillAddrLine1' => 'XXX Mahallesi XXX Caddesi No 55 Daire 1', /** * BillAddrPostCode: Kullanılan kart ile ilişkili kart hamilinin fatura adresindeki posta kodu. */ 'BillAddrPostCode' => '34000', /** * BillAddrState: CardHolderData alanı içerisinde gönderilmesi beklenen ödemede kullanılan kart ile ilişkili kart hamilinin fatura adresindeki il veya eyalet bilgisi kodu. * ISO 3166-2'de tanımlı olan il/eyalet kodu olmalıdır. */ 'BillAddrState' => '40', /** * Email: Kullanılan kart ile ilişkili kart hamilinin iş yerinde oluşturduğu hesapta kullandığı email adresi. * Maksimum 254 karakter uzunluğunda olmalıdır. */ 'Email' => 'xxxxx@gmail.com', 'MobilePhone' => [ /** * Cc: Kullanılan kart ile ilişkili kart hamilinin cep telefonuna ait ülke kodu. 1-3 karakter uzunluğunda olmalıdır. */ 'Cc' => '90', /** * Subscriber: Kullanılan kart ile ilişkili kart hamilinin cep telefonuna ait abone numarası. * Maksimum 15 karakter uzunluğunda olmalıdır. */ 'Subscriber' => '1234567899', ], ], ]; $requestData = $event->getRequestData(); $requestData = \array_merge_recursive($requestData, $additionalRequestDataForKuveyt); $event->setRequestData($requestData); } }
然后您需要在
AppServiceProvider
中注册这个新的监听器。# /app/Providers/AppServiceProvider.php namespace App\Providers; class AppServiceProvider extends ServiceProvider { public function boot(): void { // ... \Illuminate\Support\Facades\Event::listen( \Mews\Pos\Event\RequestDataPreparedEvent::class, \App\Listeners\KuveytPosV2RequestDataPreparedEventListener::class ); } }
3D Secure支付示例使用
<?php namespace App\Http\Controllers; use Illuminate\Container\Container; use Illuminate\Http\Request; use Mews\Pos\Entity\Card\CreditCardInterface; use Mews\Pos\Exceptions\CardTypeNotSupportedException; use Mews\Pos\Exceptions\CardTypeRequiredException; use Mews\Pos\Exceptions\HashMismatchException; use Mews\Pos\Factory\CreditCardFactory; use Mews\Pos\Gateways\PayFlexV4Pos; use Mews\Pos\PosInterface; class SingleBankThreeDSecurePaymentController extends Controller { private string $paymentModel = PosInterface::MODEL_3D_SECURE; public function __construct( private PosInterface $pos, Container $container, ) { // // Pos servise alternatif erişim yöntemi: // // "kuveytpos" laravel-pos.php'de tanımladığınız isim olur. // $kuveytPos = $container->get('laravel-pos:gateway:kuveytpos'); // // // birden fazla banka varsa tag // $allPosServices = $container->tagged('laravel-pos:gateway'); // foreach ($allPosServices as $bank) { // if ('kuveytpos' === $bank->getAccount()->getBank()) { // // pos found // } // } } /** * route: /single-bank/payment/3d/form * Kullanicidan kredi kart bilgileri alip buraya POST ediyoruz */ public function form(Request $request) { $session = $request->getSession(); $transaction = $request->get('tx', PosInterface::TX_TYPE_PAY_AUTH); $callbackUrl = url("/single-bank/payment/3d/response"); $order = $this->createNewOrder( $this->paymentModel, $callbackUrl, $request->getClientIp(), $request->get('currency', PosInterface::CURRENCY_TRY), $request->get('installment'), ); $session->set('order', $order); $card = $this->createCard($this->pos, $request->request->all()); /** * PayFlex'te provizyonu (odemeyi) tamamlamak icin tekrar kredi kart bilgileri isteniyor, * bu yuzden kart bilgileri kaydediyoruz */ if ($this->pos::class === PayFlexV4Pos::class) { // Laravel 8'de set() yerine put() metodu kullanmanız gerekiyor. $session->set('card', $request->request->all()); } $session->set('tx', $transaction); try { $formData = $this->pos->get3DFormData($order, $this->paymentModel, $transaction, $card); } catch (\Throwable $e) { dd($e); } return view('redirect-form', [ 'formData' => $formData, ]); } /** * route: /single-bank/payment/3d/response * Kullanici bankadan geri buraya redirect edilir. * Bu route icin CSRF disable edilmesi gerekiyor. */ public function response(Request $request) { $session = $request->getSession(); $transaction = $session->get('tx', PosInterface::TX_TYPE_PAY_AUTH); // bankadan POST veya GET ile veri gelmesi gerekiyor if (($request->getMethod() !== 'POST') // PayFlex-CP GET request ile cevapliyor && ($request->getMethod() === 'GET' && ($this->pos::class !== \Mews\Pos\Gateways\PayFlexCPV4Pos::class || [] === $request->query->all())) ) { return redirect('/'); } $card = null; if ($this->pos::class === \Mews\Pos\Gateways\PayFlexV4Pos::class) { // bu gateway için ödemeyi tamamlarken tekrar kart bilgisi lazım. $savedCard = $session->get('card'); $card = $this->createCard($this->pos, $savedCard); } $order = $session->get('order'); if (!$order) { throw new \Exception('Sipariş bulunamadı, session sıfırlanmış olabilir.'); } try { $this->pos->payment($this->paymentModel, $order, $transaction, $card); } catch (HashMismatchException $e) { dd($e); } catch (\Exception|\Error $e) { dd($e); } $response = $this->pos->getResponse(); // iptal, iade, siparis durum sorgulama islemleri yapabilmek icin $response'u kaydediyoruz $session->set('last_response', $response); if ($this->pos->isSuccess()) { echo 'success'; } dd($response); } private function createNewOrder( string $paymentModel, string $callbackUrl, string $ip, string $currency, ?int $installment = 0, string $lang = PosInterface::LANG_TR ): array { $orderId = date('Ymd').strtoupper(substr(uniqid(sha1(time())), 0, 4)); $order = [ 'id' => $orderId, 'amount' => 10.01, 'currency' => $currency, 'installment' => $installment, 'ip' => filter_var($ip, FILTER_VALIDATE_IP, FILTER_FLAG_IPV4) ? $ip : '127.0.0.1', ]; if (in_array($paymentModel, [ PosInterface::MODEL_3D_SECURE, PosInterface::MODEL_3D_PAY, PosInterface::MODEL_3D_HOST, PosInterface::MODEL_3D_PAY_HOSTING, ], true)) { $order['success_url'] = $callbackUrl; $order['fail_url'] = $callbackUrl; } if ($lang) { //lang degeri verilmezse account (EstPosAccount) dili kullanilacak $order['lang'] = $lang; } return $order; } private function createCard(PosInterface $pos, array $card): CreditCardInterface { try { return CreditCardFactory::createForGateway( $pos, $card['number'], $card['year'], $card['month'], $card['cvv'], $card['name'], $card['type'] ?? null ); } catch (CardTypeRequiredException|CardTypeNotSupportedException $e) { dd($e); } catch (\LogicException $e) { dd($e); } } }
# /routes/web.php Route::match(['POST'], '/single-bank/payment/3d/form', [\App\Http\Controllers\SingleBankThreeDSecurePaymentController::class, 'form']); Route::match(['GET','POST'], '/single-bank/payment/3d/response', [\App\Http\Controllers\SingleBankThreeDSecurePaymentController::class, 'response']);
<!--/resources/views/redirect-form.blade.php--> <form method="{{ $formData['method'] }}" action="{{ $formData['gateway'] }}" class="redirect-form" role="form"> @foreach($formData['inputs'] as $key => $value) <input type="hidden" name="{{ $key }}" value="{{ $value }}"> @endforeach <div class="text-center">Redirecting...</div> <hr> <div class="form-group text-center"> <button type="submit" class="btn btn-lg btn-block btn-success">Submit</button> </div> </form>
故障排除
- 错误: "cURL错误60:SSL证书问题:无法获取本地发行者证书(请参阅https://curl.haxx.se/libcurl/c/libcurl-errors.html)for https://..." 通常您可以在本地环境中遇到这个问题。当您的本地环境中没有CA证书时会产生。在这种情况下,尝试在服务器上运行。
许可证
MIT