定制 emre-tarhan/kuveytturk-vpos-laravel-sdk 二次开发

按需修改功能、优化性能、对接业务系统,提供一站式技术支持

邮箱:yvsm@zunyunkeji.com | QQ:316430983 | 微信:yvsm316

emre-tarhan/kuveytturk-vpos-laravel-sdk

Composer 安装命令:

composer require emre-tarhan/kuveytturk-vpos-laravel-sdk

包简介

Kuveyt Türk Sanal Pos (Virtual POS) Laravel SDK with 3D Secure 2.0 support

README 文档

README

Latest Version PHP License

Kuveyt Turk Sanal POS entegrasyonu icin kapsamli Laravel SDK. Tam 3D Secure 2.0 destegi.

Ozellikler

  • 3D Secure 2.0 Tam Destek — Iki asamali odeme akisi
  • Iki Asamali Odeme: Kart Dogrulama + Provizyon (Odeme Alma)
  • Taksit Destegi — 24 aya kadar taksit imkani
  • Ertelemeli Odeme (Harcama Oteleme) — Esnek odeme planlama
  • Hash Veri Dogrulama — SHA1 tabanli istek dogrulama
  • Test & Produksiyon Ortamlari — Ayri endpoint'ler
  • Satis / Iptal / Iade / Kismi Iade Islemleri — Tam islem yasam dongusu
  • WCF SOAP Servis Entegrasyonu — Iptal/iade islemleri icin
  • Kapsamli Hata Yonetimi — Tum Kuveyt Turk hata kodlari
  • Laravel 12.x & 13.x Uyumlu
  • PHP 8.1, 8.2, 8.3, 8.4 Destegi

Gereksinimler

  • PHP: 8.1, 8.2, 8.3 veya 8.4
  • Laravel: 12.x veya 13.x
  • PHP Eklentileri: curl, libxml, openssl

Kurulum

composer require emre-tarhan/kuveytturk-vpos-laravel-sdk

Ayarlari Yayinlama

php artisan vendor:publish --tag=kuveytturk-vpos-config

Veya kurulum komutunu kullanin:

php artisan kuveytturk:install

Bu islem ayar dosyasini config/kuveytturk-vpos.php konumuna yayinlayacaktir.

Yapilandirma

Kuveyt Turk kimlik bilgilerinizi .env dosyasina ekleyin:

KUVEYTTURK_MERCHANT_ID=uye_isyeri_numaraniz
KUVEYTTURK_CUSTOMER_ID=musteri_numaraniz
KUVEYTTURK_USERNAME=api_kullanici_adiniz
KUVEYTTURK_PASSWORD=api_sifreniz
KUVEYTTURK_ENVIRONMENT=test # veya 'production'

Veya config/kuveytturk-vpos.php dosyasindan yapilandirin:

return [
    'merchant_id' => env('KUVEYTTURK_MERCHANT_ID', ''),
    'customer_id' => env('KUVEYTTURK_CUSTOMER_ID', ''),
    'username' => env('KUVEYTTURK_USERNAME', ''),
    'password' => env('KUVEYTTURK_PASSWORD', ''),
    'environment' => env('KUVEYTTURK_ENVIRONMENT', 'test'),
    'timeout' => env('KUVEYTTURK_TIMEOUT', 60),
    'connect_timeout' => env('KUVEYTTURK_CONNECT_TIMEOUT', 30),
];

Kullanim

Temel Satis (Tam 3D Akis)

use EmreTarhan\KuveytTurkVPos\Services\KuveytTurkVPos;
use EmreTarhan\KuveytTurkVPos\Dto\SaleRequest;
use EmreTarhan\KuveytTurkVPos\Enums\CurrencyCode;

// Servis konteynerinden enjekte et veya app'ten cozumle
$vpos = app(KuveytTurkVPos::class);

$request = new SaleRequest(
    merchantOrderId: 'ORDER-' . time(),
    amount: 100.00, // 100 TL - dahili olarak 10000'e donusturulur
    okUrl: 'https://siteniz.com/odeme/basarili',
    failUrl: 'https://siteniz.com/odeme/basarisiz',
    cardHolderName: 'Ahmet Yilmaz',
    cardNumber: '5188961939192544',
    cardExpireDateYear: '25',
    cardExpireDateMonth: '06',
    cardCVV2: '929',
    email: 'musteri@ornek.com',
    clientIp: request()->ip(),
    billAddrCity: 'Istanbul',
    billAddrCountry: '792', // Turkiye ulke kodu
    billAddrLine1: 'Ornek Sokak No:123',
    billAddrPostCode: '34000',
    billAddrState: '34',
    Cc: 'Ahmet Yilmaz',
    subscriber: 'musteri@ornek.com',
    currencyCode: CurrencyCode::TRY,
    installmentCount: 0, // 0 = taksitsiz, 1-24 arasi taksit
);

$response = $vpos->sale($request);

if ($response->isSuccessful()) {
    // Odeme basarili
    echo "Islem onaylandi! Siparis No: " . $response->orderId;
} else {
    // Odeme basarisiz
    echo "Odeme basarisiz: " . $response->responseMessage;
}

Iki Asamali Odeme (Manuel Kontrol)

Odeme akisi uzerinde daha fazla kontrole ihtiyaciniz varsa:

Asama 1: Kart Dogrulama

use EmreTarhan\KuveytTurkVPos\Dto\VerifyCardRequest;

$verifyRequest = new VerifyCardRequest(
    merchantOrderId: 'ORDER-' . time(),
    amount: 150.00,
    okUrl: 'https://siteniz.com/odeme/basarili',
    failUrl: 'https://siteniz.com/odeme/basarisiz',
    cardHolderName: 'Ahmet Yilmaz',
    cardNumber: '5188961939192544',
    cardExpireDateYear: '25',
    cardExpireDateMonth: '06',
    cardCVV2: '929',
    email: 'musteri@ornek.com',
    clientIp: request()->ip(),
    billAddrCity: 'Istanbul',
    billAddrCountry: '792',
    billAddrLine1: 'Ornek Sokak No:123',
    billAddrPostCode: '34000',
    billAddrState: '34',
    Cc: 'Ahmet Yilmaz',
    subscriber: 'musteri@ornek.com',
    currencyCode: CurrencyCode::TRY,
    installmentCount: 3, // 3 ay taksit
);

$verifyResponse = $vpos->verifyCard($verifyRequest);

// Asama 2 icin MD degerini saklayin
$mdValue = $verifyResponse->md; // Provizyon icin gerekli
$orderId = $verifyResponse->orderId;

Asama 2: Provizyon (Odeme Tamamlama)

use EmreTarhan\KuveytTurkVPos\Dto\ProvisionRequest;

$provisionRequest = new ProvisionRequest(
    merchantOrderId: 'ORDER-' . time(),
    amount: 150.00,
    md: $asama1denGelenMdDegeri,
    okUrl: 'https://siteniz.com/odeme/basarili',
    failUrl: 'https://siteniz.com/odeme/basarisiz',
    currencyCode: CurrencyCode::TRY,
    installmentCount: 3,
);

$provisionResponse = $vpos->provision($provisionRequest);

if ($provisionResponse->isSuccessful()) {
    // Odeme tamamlandi
    echo "Provizyon basarili! RRN: " . $provisionResponse->rrn;
}

Islem Iptali (Ayni Gun)

use EmreTarhan\KuveytTurkVPos\Dto\CancelRequest;
use EmreTarhan\KuveytTurkVPos\Enums\CurrencyCode;

$cancelRequest = new CancelRequest(
    merchantOrderId: 'ORDER-12345',
    amount: 100.00,
    provisionNumber: '123456', // Orijinal satis isleminden
    rrn: '789012345',          // Referans numarasi
    stan: '654321',            // Sistem iz numarasi
    orderId: 'orijinal-siparis-no',
    currencyCode: CurrencyCode::TRY,
);

$cancelResponse = $vpos->cancel($cancelRequest);

if ($cancelResponse->isSuccessful()) {
    echo "Islem basariyla iptal edildi!";
}

Iade (Gun Sonu Sonrasi)

use EmreTarhan\KuveytTurkVPos\Dto\RefundRequest;

$refundRequest = new RefundRequest(
    merchantOrderId: 'ORDER-12345',
    amount: 100.00,
    provisionNumber: '123456',
    rrn: '789012345',
    stan: '654321',
    orderId: 'orijinal-siparis-no',
    currencyCode: CurrencyCode::TRY,
);

$refundResponse = $vpos->refund($refundRequest);

if ($refundResponse->isSuccessful()) {
    echo "Iade basariyla gerceklestirildi!";
}

Kismi Iade

use EmreTarhan\KuveytTurkVPos\Dto\PartialRefundRequest;

$partialRefundRequest = new PartialRefundRequest(
    merchantOrderId: 'ORDER-12345',
    amount: 50.00, // Kismi tutar
    provisionNumber: '123456',
    rrn: '789012345',
    stan: '654321',
    orderId: 'orijinal-siparis-no',
    currencyCode: CurrencyCode::TRY,
);

$partialRefundResponse = $vpos->partialRefund($partialRefundRequest);

if ($partialRefundResponse->isSuccessful()) {
    echo "Kismi iade basariyla gerceklestirildi!";
}

Gercek Entegrasyon Ornegi (3D Secure Akisi)

Asagida produksiyon ortaminda kullanilan, tam 3D Secure odeme akisi ornegi bulunmaktadir. Bu akis 5 asamadan olusur: odeme baslatma, bankaya yonlendirme, callback karsilama, provizyon tamamlama ve siparisi sonuclandirma.

Asama 1: Servis Konteynerine Kayit

// App\Providers\AppServiceProvider::register()
use EmreTarhan\KuveytTurkVPos\Services\KuveytTurkVPos;

$this->app->singleton(KuveytTurkVPos::class, function () {
    return KuveytTurkVPos::fromConfig(config('kuveytturk-vpos'));
});

Asama 2: Odeme Baslatma (Controller)

Kart dogrulama islemi bankadan HTML dondurur. Bu HTML'i tarayicida render etmeniz gerekir — otomatik olarak bankanin 3D Secure sayfasina yonlendiren bir form icerir.

use EmreTarhan\KuveytTurkVPos\Services\KuveytTurkVPos;
use EmreTarhan\KuveytTurkVPos\Dto\VerifyCardRequest;
use EmreTarhan\KuveytTurkVPos\Enums\CurrencyCode;

public function odeme(Request $request, KuveytTurkVPos $vpos)
{
    $verifyRequest = new VerifyCardRequest(
        merchantOrderId: 'ORDER-' . time(),
        amount: 100.00,
        okUrl: route('odeme.callback.basarili'),
        failUrl: route('odeme.callback.basarisiz'),
        cardHolderName: $request->input('kart_sahibi'),
        cardNumber: $request->input('kart_numarasi'),
        cardExpireDateYear: $request->input('kart_yil'),   // 2 haneli: '28'
        cardExpireDateMonth: $request->input('kart_ay'),    // 2 haneli: '12'
        cardCVV2: $request->input('kart_cvv'),
        email: $request->input('email'),
        clientIp: $request->ip(),
        billAddrCity: 'Istanbul',
        billAddrCountry: '792',
        billAddrLine1: 'Ornek Sokak',
        billAddrPostCode: '34000',
        billAddrState: '34',
        Cc: $request->input('kart_sahibi'),
        subscriber: $request->input('email'),
        currencyCode: CurrencyCode::TRY,
        installmentCount: 0,
    );

    $hashCalculator = $vpos->getHashCalculator();
    $hashData = $verifyRequest->generateHash($hashCalculator);
    $xml = $verifyRequest->toXml($hashData);

    // Bankanin kart dogrulama endpoint'ine gonder
    $response = Http::withHeaders([
        'Content-Type' => 'application/xml',
    ])->withBody($xml, 'application/xml')
      ->post($vpos->getCardVerificationUrl());

    $body = $response->body();

    // Banka 3D Secure yonlendirme HTML'i dondurur — session'a kaydet ve tarayicida render et
    if (str_contains($body, '<html') || str_contains($body, '<form')) {
        session(['secure3d_html' => $body]);
        return redirect()->route('odeme.secure3d');
    }

    // Dogrudan basarisizlik (3D Secure yonlendirmesi yok)
    return back()->withError('Odeme baslatma basarisiz.');
}

Asama 3: 3D Secure Sayfasini Render Etme (Frontend)

Bankanin HTML'i otomatik gonderilen bir form icerir. Gizli bir div'de gosterip otomatik gonderin:

<!-- resources/views/odeme/secure3d.blade.php -->
<div id="secure3d-container" style="display:none;">
    {!! session('secure3d_html') !!}
</div>
<script>
    setTimeout(function() {
        document.getElementById('secure3d-container').querySelector('form').submit();
    }, 500);
</script>
<p>3D Secure dogrulamasina yonlendiriliyorsunuz...</p>

Asama 4: Banka Callback'inin Karsilanmasi (CSRF/Session Middleware Haric)

Onemli: Banka callback URL'lerinize cross-site POST gonderir. Bu route'lar middleware gruplarinin disinda olmalidir (CSRF ve session yok):

// bootstrap/app.php veya routes/web.php — middleware gruplarinin DISINDA
Route::post('/odeme/callback/basarili', [OdemeCallbackController::class, 'basarili'])
    ->name('odeme.callback.basarili');
Route::post('/odeme/callback/basarisiz', [OdemeCallbackController::class, 'basarisiz'])
    ->name('odeme.callback.basarisiz');

Asama 5: Provizyon (Odeme Tamamlama)

use EmreTarhan\KuveytTurkVPos\Dto\ProvisionRequest;
use EmreTarhan\KuveytTurkVPos\Enums\CurrencyCode;

public function basarili(Request $request, KuveytTurkVPos $vpos)
{
    // Banka URL-encoded XML olarak AuthenticationResponse gonderir
    $rawXml = urldecode($request->getContent());

    // XML'i guvenli sekilde cozumle
    libxml_use_internal_errors(true);
    $dom = new \DOMDocument();
    $dom->loadXML($rawXml, LIBXML_NONET | LIBXML_NOCDATA);
    libxml_clear_errors();
    $xpath = new \DOMXPath($dom);

    $getir = fn (string $tag): ?string =>
        ($nodes = $xpath->query("//*[local-name()='{$tag}']")) && $nodes->length > 0
            ? $nodes->item(0)->textContent : null;

    $md = $getir('MD');
    $orderId = $getir('OrderId');
    $responseCode = $getir('ResponseCode');
    $merchantOrderId = $getir('MerchantOrderId');

    // Hash dogrulama: SHA1_base64(MerchantOrderId + ResponseCode + OrderId + HashPassword)
    $hashCalculator = $vpos->getHashCalculator();
    $hashPassword = $hashCalculator->getHashPassword();
    $beklenenHash = base64_encode(sha1($merchantOrderId . $responseCode . $orderId . $hashPassword, true));
    $gelenHash = $getir('HashData');

    if (!hash_equals($beklenenHash, $gelenHash)) {
        // Hash uyumsuzlugu — callback'i reddet
        return response('Gecersiz hash', 400);
    }

    // Asama 2: Provizyon
    $provisionRequest = new ProvisionRequest(
        merchantOrderId: $merchantOrderId,
        amount: 100.00,
        md: $md,
        okUrl: route('odeme.callback.basarili'),
        failUrl: route('odeme.callback.basarisiz'),
        currencyCode: CurrencyCode::TRY,
        installmentCount: 0,
    );

    $hashData = $provisionRequest->generateHash($hashCalculator);
    $provisionXml = $provisionRequest->toXml($hashData);

    $response = Http::withHeaders([
        'Content-Type' => 'application/xml',
    ])->withBody($provisionXml, 'application/xml')
      ->post($vpos->getProvisionUrl());

    // Provizyon yanitini cozumle ve siparisi sonuclandir...
    if ($responseCode === '00') {
        // Odeme basarili — siparis durumunu guncelle
    }
}

CSP Basliklari (Gerekli)

3D Secure yonlendirme formunun engellenmemesi icin Kuveyt Turk domainlerini Content Security Policy'nize ekleyin:

// Middleware veya yapilandirma
'connect-src' => [..., 'https://*.kuveytturk.com.tr'],
'form-action' => [..., 'https://*.kuveytturk.com.tr'],

Yanit Nesneleri

SaleResponse

Ozellik Aciklama
isSuccessful() Boolean — islem onaylandiysa true
responseCode Kuveyt Turk yanit kodu ("00" = basarili)
responseMessage Okunabilir yanit mesaji
orderId Banka siparis numarasi
provisionNumber Provizyon numarasi
rrn Referans numarasi
stan Sistem iz numarasi
transactionTime Islem zaman damgasi
merchantOrderId Sizin siparis numaraniz
md 3D Secure MD degeri

Hata Yonetimi

use EmreTarhan\KuveytTurkVPos\Services\KuveytTurkVPos;
use EmreTarhan\KuveytTurkVPos\Exceptions\KuveytTurkVPosException;
use EmreTarhan\KuveytTurkVPos\Enums\ErrorCode;

try {
    $response = $vpos->sale($request);

    if ($response->isSuccessful()) {
        // Basarili islemi ele al
    } else {
        // Is hatasini ele al
        $errorCode = ErrorCode::fromString($response->responseCode);
        echo "Hata: " . $errorCode->label();
    }
} catch (KuveytTurkVPosException $e) {
    // Baglanti/dogrulama hatalarini ele al
    echo "Hata: " . $e->getMessage();
}

Hata Kodlari

Kod Aciklama
00 Otorizasyon verildi / Islem basarili
01 Gecersiz kart numarasi
05 Yetersiz bakiye
12 Gecersiz uye isyeri
14 Gecersiz islem / CVV
17 Kart limiti asildi
54 Kart suresi dolmus
59 Sahtekarlik suphesi
70 Mukerrer siparis
91 Zaman asimi
96 Sistem hatasi
99 Hashdata uyusmazligi

Tutar Formatı

Tum tutarlar gercek deger olarak belirtilmelidir (ornegin 100.50 = 100 TL 50 kurus).

SDK bankanin formatina otomatik donusturur (tutar x 100, ornegin 100.50 TL = 10050).

// Hepsi ayni sonucu verir:
$request = new SaleRequest(..., amount: 100.50, ...);
$request = new SaleRequest(..., amount: '100.50', ...);
$request = new SaleRequest(..., amount: 10050, ...); // Zaten banka formatinda

Test Ortami

Sandbox testleri icin asagidaki test kartini kullanin:

Alan Deger
Kart Numarasi 5188 9619 3919 2544
CVV 929
Son Kullanma 06/25
3D Sifre 123456

Test Endpoint'leri:

  • Kart Dogrulama: https://boatest.kuveytturk.com.tr/boa.virtualpos.services/Home/ThreeDModelPayGate
  • Provizyon: https://boatest.kuveytturk.com.tr/boa.virtualpos.services/Home/ThreeDModelProvisionGate

Produksiyon Endpoint'leri:

  • Kart Dogrulama: https://sanalpos.kuveytturk.com.tr/ServiceGateWay/Home/ThreeDModelPayGate
  • Provizyon: https://sanalpos.kuveytturk.com.tr/ServiceGateWay/Home/ThreeDModelProvisionGate

Test Calistirma

composer test

Katkida Bulunma

Katkilar memnuniyetle karsilanir! Lutfen bir Pull Request gonderin.

Lisans

MIT Lisansi. Detaylar icin LICENSE dosyasina bakin.

Destek

Sorular ve sorunlar icin lutfen GitHub'da issue acin: https://github.com/emre-tarhan/kuveytturk-vpos-laravel-sdk

emre-tarhan/kuveytturk-vpos-laravel-sdk 适用场景与选型建议

emre-tarhan/kuveytturk-vpos-laravel-sdk 是一款 基于 PHP 开发的 Composer 扩展包,目前已累计 0 次下载、GitHub Stars 达 0, 最近一次更新时间为 2026 年 06 月 12 日, 在 PHP 生态内属于活跃度较高的组件。

它主要适用于以下技术方向: 「payment」 「laravel」 「Bank」 「turkey」 「pos」 「kuveytturk」 等业务场景。在实际项目中,围绕这些方向常见需要落地的问题包括:接口对接、性能调优、并发安全、与既有框架(Laravel / ThinkPHP / Yii / Webman 等)的兼容适配,以及生产环境的日志埋点与稳定性保障。

我们在过去多个企业项目中使用过 emre-tarhan/kuveytturk-vpos-laravel-sdk 或与其功能相近的方案,如果你在选型或落地过程中遇到问题,例如 版本兼容、二次改造、私有化封装、与内部系统对接、生产 BUG 排查,欢迎联系我们协助评估。

围绕 emre-tarhan/kuveytturk-vpos-laravel-sdk 我们能提供哪些服务?
定制开发 / 二次开发

基于 emre-tarhan/kuveytturk-vpos-laravel-sdk 在你已有业务上做功能扩展、字段裁剪、UI 适配、与内部账号 / 权限 / 日志系统的深度对接。

BUG 修复 & 性能优化

线上偶发问题、内存泄漏、慢查询、并发异常等排查修复;针对高流量场景做缓存、队列、索引层面的调优。

项目外包 & 长期维护

承接完整的项目从需求 → 设计 → 开发 → 上线 → 长期运维;也可按月提供技术保姆服务。

yvsm@zunyunkeji.com QQ:316430983 微信:yvsm316 西安尊云信息科技 · 专注 PHP / Go / 分布式系统研发

统计信息

  • 总下载量: 0
  • 月度下载量: 0
  • 日度下载量: 0
  • 收藏数: 0
  • 点击次数: 44
  • 依赖项目数: 0
  • 推荐数: 0

GitHub 信息

  • Stars: 0
  • Watchers: 0
  • Forks: 0
  • 开发语言: PHP

其他信息

  • 授权协议: MIT
  • 更新时间: 2026-06-12