klc/tami-laravel 问题修复 & 功能扩展

解决BUG、新增功能、兼容多环境部署,快速响应你的开发需求

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

klc/tami-laravel

Composer 安装命令:

composer require klc/tami-laravel

包简介

Tami sanal POS için Laravel-native paket — tip-güvenli, test edilebilir, güvenli

README 文档

README

Tami sanal POS için Laravel-native paket. Tip-güvenli, test edilebilir, güvenli.

Kurulum

composer require klc/tami-laravel

Laravel 10.x+ ve PHP 8.1+ gerektirir. Paket auto-discovery ile otomatik yüklenir.

Konfigürasyon

php artisan vendor:publish --tag=tami-config

.env dosyasına aşağıdaki değişkenleri ekleyin:

TAMI_ENVIRONMENT=sandbox
TAMI_MERCHANT_ID=77006950
TAMI_TERMINAL_ID=84006953
TAMI_SECRET_KEY=your-secret-key
TAMI_JWK_KID=your-jwk-kid
TAMI_JWK_K=your-jwk-k
# Normal API response securityHash doğrulaması, Tami algoritması netleşene kadar kapalı kalmalıdır.
TAMI_RESPONSE_HASH_ENABLED=false

Canlı ortam için:

TAMI_ENVIRONMENT=production
TAMI_MERCHANT_ID=your-production-merchant
TAMI_TERMINAL_ID=your-production-terminal
TAMI_SECRET_KEY=your-production-secret
TAMI_JWK_KID=your-production-kid
TAMI_JWK_K=your-production-k

Kullanım

Ödeme (Payment)

use Klc\Tami\Facades\Tami;
use Klc\Tami\DTOs\CardDto;
use Klc\Tami\DTOs\AddressDto;
use Klc\Tami\DTOs\BuyerDto;
use Klc\Tami\DTOs\BasketItemDto;
use Klc\Tami\DTOs\BasketDto;
use Klc\Tami\DTOs\Payment\AuthRequestDto;
use Klc\Tami\Enums\ItemType;
use Klc\Tami\Enums\PaymentChannel;

// Kart
$card = new CardDto(
    number: '4824910501747014',
    holderName: 'Örnek Kullanıcı',
    cvv: '123',
    expireMonth: 12,
    expireYear: 2026,
);

// Adres
$address = new AddressDto(
    address: 'Örnek Mah. Test Sk. No:1',
    city: 'İstanbul',
    companyName: 'Örnek Firma',
    country: 'Türkiye',
    district: 'Kadıköy',
    contactName: 'Örnek İletişim',
    phoneNumber: '05555555555',
    zipCode: '34700',
);

// Alıcı
$buyer = new BuyerDto(
    ipAddress: '127.0.0.1',
    buyerId: 'buyer-001',
	    name: 'Örnek',
	    surName: 'Kullanıcı',
	    emailAddress: 'ornek@eposta.com',
	    phoneNumber: '05555555555',
	    // Aşağıdaki alanlar Tami dokümanında opsiyonel/senaryoya bağlıdır.
	    identityNumber: '11111111111',
	    city: 'İstanbul',
	    country: 'Türkiye',
	    zipCode: '34700',
	    registrationAddress: 'Örnek Mah. Test Sk. No:1',
	    registrationDate: '2023-01-01T10:00:00',
	    lastLoginDate: '2023-06-01T10:00:00',
);

// Sepet
$item = new BasketItemDto(
	    itemId: 'item-001',
	    name: 'Örnek Ürün',
	    itemType: ItemType::Physical,
	    numberOfProducts: 1,
	    totalPrice: '100.00',
	    unitPrice: '100.00',
	    category: 'Elektronik',
	    subCategory: 'Bilgisayar',
);

$basket = new BasketDto('basket-001', [$item]);

// Ödeme isteği
	$dto = new AuthRequestDto(
	    orderId: 'order-' . uniqid(),
	    amount: '100.00',
    currency: 'TRY',
    installmentCount: 1,
    paymentGroup: 'PRODUCT',
    paymentChannel: PaymentChannel::Web,
    card: $card,
    billingAddress: $address,
    shippingAddress: $address,
    buyer: $buyer,
    basket: $basket,
);

// Ödemeyi gerçekleştir
$response = Tami::payment()->auth($dto);

if ($response->isSuccess()) {
    echo "Ödeme başarılı! Sipariş: " . $response->getOrderId();
} else {
    echo "Hata: " . $response->getErrorCode() . " - " . $response->getErrorMessage();
}

3D Secure Ödeme

// Geri dönüş URL'si ile 3DS başlatma
	$authDto = new AuthRequestDto(
	    orderId: 'order-' . uniqid(),
	    amount: '100.00',
    currency: 'TRY',
    installmentCount: 1,
    paymentGroup: 'PRODUCT',
    paymentChannel: PaymentChannel::Web,
    card: $card,
    billingAddress: $address,
    shippingAddress: $address,
    buyer: $buyer,
    basket: $basket,
    callbackUrl: 'https://example.com/tami/callback',
);

$response = Tami::payment()->auth($authDto);

if ($response->is3dsRequired()) {
    echo $response->getHtmlContent(); // Banka 3DS sayfasına yönlendir
}

3DS Callback Yönetimi

Paket otomatik olarak POST /tami/callback ve GET /tami/callback route'larını kaydeder. Callback payload'ında hashedData varsa paket Tami'nin 3DS HMAC-SHA256 formülüne göre doğrular; doğrulama başarısızsa /payment/complete-3ds çağrısı yapılmadan hata event'i yayınlanır. Başarılı/başarısız durumlar için event dinleyicileri:

// EventServiceProvider.php
use Klc\Tami\Events\TamiPaymentSucceeded;
use Klc\Tami\Events\TamiPaymentFailed;

protected $listen = [
    TamiPaymentSucceeded::class => [
        // Siparişi tamamla, stok düş, vs.
    ],
    TamiPaymentFailed::class => [
        // Hata logla, kullanıcıyı bilgilendir
    ],
];

Ön Otorizasyon (Pre-Auth)

$preAuthResponse = Tami::payment()->preAuth($authDto);

// Daha sonra kapama (capture)
use Klc\Tami\DTOs\Payment\PostAuthRequestDto;

	$postAuthDto = new PostAuthRequestDto(
	    orderId: $preAuthResponse->getOrderId(),
	    amount: '100.00', // Kısmi kapama için daha düşük tutar
);
$captureResponse = Tami::payment()->postAuth($postAuthDto);

İptal / İade

use Klc\Tami\DTOs\Payment\ReverseRequestDto;

// Tam iade
$reverseDto = new ReverseRequestDto(orderId: 'order-123');
$reverseResponse = Tami::payment()->reverse($reverseDto);

// Kısmi iade
	$reverseDto = new ReverseRequestDto(
	    orderId: 'order-123',
	    amount: '50.00',
    reason: 'Kısmi iade',
);
$reverseResponse = Tami::payment()->reverse($reverseDto);

Sipariş Sorgulama

use Klc\Tami\DTOs\Payment\QueryRequestDto;

$queryDto = new QueryRequestDto(
    orderId: 'order-123',
    isTransactionDetail: true,
);
$queryResponse = Tami::payment()->query($queryDto);

echo "Sipariş Durumu: " . $queryResponse->getOrderStatus();
echo "Ödeme Durumu: " . $queryResponse->getPaymentStatus();
echo "Taksit Sayısı: " . $queryResponse->getInstallmentCount();

Taksit ve Kart Bilgisi

use Klc\Tami\DTOs\Installment\BinInfoRequestDto;
use Klc\Tami\DTOs\Installment\InstallmentInfoRequestDto;

// BIN sorgulama
$binDto = new BinInfoRequestDto('48249105');
$binResponse = Tami::installment()->binInfo($binDto);

echo "Banka: " . $binResponse->getBankName();
echo "Kart Tipi: " . $binResponse->getCardType(); // CREDIT/DEBIT
echo "Kart Ağı: " . $binResponse->getCardOrg();   // VISA/MASTERCARD/TROY/AMEX

// Taksit seçenekleri
$installmentDto = new InstallmentInfoRequestDto('48249105');
$installmentResponse = Tami::installment()->installmentInfo($installmentDto);

$installments = $installmentResponse->getInstallments(); // [1, 3, 5]
$requires3ds = $installmentResponse->isForce3ds();
$requiresCvv = $installmentResponse->isForceCvc();

Bonus / Puan Sorgulama

use Klc\Tami\DTOs\Vas\BonusInquiryRequestDto;

$bonusDto = new BonusInquiryRequestDto(
    ipAddress: '127.0.0.1',
    emailAddress: 'ornek@eposta.com',
    cardNumber: '4824910501747014',
    expireMonth: 12,
    expireYear: 2026,
    currencyCode: 949, // TRY için 949
	    amount: '100.00',
);
$bonusResponse = Tami::vas()->bonusInquiry($bonusDto);

if ($bonusResponse->isApproved()) {
    foreach ($bonusResponse->getRewardList() as $reward) {
        echo $reward['type'] . ': ' . $reward['amount'];
    }
}

Puanlı Satış

use Klc\Tami\DTOs\RewardDto;
use Klc\Tami\DTOs\RewardToBeUsedDto;

	$reward = new RewardDto(type: 'BNS', amount: '20.00');
$rewardToBeUsed = new RewardToBeUsedDto([$reward]);

$dto = new AuthRequestDto(
    // ... diğer alanlar
    orderId: 'order-' . uniqid(),
	    amount: '100.00',
    currency: 'TRY',
    installmentCount: 1,
    paymentGroup: 'PRODUCT',
    paymentChannel: PaymentChannel::Web,
    card: $card,
    billingAddress: $address,
    shippingAddress: $address,
    buyer: $buyer,
    basket: $basket,
    isRewardToBeUsed: true,
    rewardToBeUsed: $rewardToBeUsed,
);

$response = Tami::payment()->auth($dto);

Ortak Ödeme Sayfası (Hosted Payment)

Tami'nin sunduğu ortak ödeme sayfası entegrasyonu — işyerinin kart bilgisi toplamasına gerek kalmadan, ödeme sayfası Tami tarafından sunulur. Masterpass ile kayıtlı kartlarla veya yeni kart bilgisiyle ödeme yapılabilir.

Token geçerlilik süresi: Test ortamında 15 dakika, prod ortamda 6 dakika. Token alınır alınmaz kullanıcı sayfaya yönlendirilmelidir.

use Klc\Tami\Facades\Tami;
use Klc\Tami\DTOs\HostedToken\HostedTokenRequestDto;

// 1. Token oluştur
$dto = new HostedTokenRequestDto(
    amount: 150.00,
    orderId: 'order-' . uniqid(),
    successCallbackUrl: 'https://example.com/odeme/basarili',
    failCallbackUrl: 'https://example.com/odeme/basarisiz',
    mobilePhoneNumber: '905343000201', // 905xxxxxxxxx formatında zorunlu
    data: ['key-1' => 'extra-info'],   // opsiyonel
);

$response = Tami::hosted()->createToken($dto);

// 2. Kullanıcıyı ortak ödeme sayfasına yönlendir
return redirect($response->getPaymentUrl());
// → https://portal.tami.com.tr/hostedPaymentPage?token=...

Callback yönetimi: Başarılı ödemede Tami, successCallbackUrl'e yönlendirme yapar. Callback verisi taşımadığı için işlem durumunu Query servisi ile sorgulayın:

// successCallbackUrl handler'ında:
$queryResponse = Tami::payment()->query(new QueryRequestDto(
    orderId: $orderId,
    isTransactionDetail: true,
));

if ($queryResponse->getPaymentStatus() === 'SUCCESS') {
    // Siparişi tamamla
}

Not: failCallbackUrl şu an için Tami tarafından kullanılmamaktadır, successCallbackUrl ile aynı değer verilebilir. Hata durumunda kullanıcıya Tami sayfasında hata mesajı gösterilir.

Hata Yönetimi

use Klc\Tami\Exceptions\TamiConnectionException;
use Klc\Tami\Exceptions\TamiAuthException;
use Klc\Tami\Exceptions\TamiApiException;
use Klc\Tami\Exceptions\TamiValidationException;
use Klc\Tami\Exceptions\TamiSecurityException;

try {
    $response = Tami::payment()->auth($dto);
} catch (TamiValidationException $e) {
    // DTO validasyon hatası
    $errors = $e->errors; // MessageBag
} catch (TamiConnectionException $e) {
    // Bağlantı hatası
} catch (TamiAuthException $e) {
    // Kimlik doğrulama hatası (HTTP 401)
} catch (TamiApiException $e) {
    // API hatası
    echo $e->errorCode;
    echo $e->errorMessage;
    echo $e->errorGroup;
} catch (TamiSecurityException $e) {
    // Security hash doğrulama hatası
}

Route Konfigürasyonu

# Route'ları kapat
TAMI_ROUTES_ENABLED=false

# Route ön eki
TAMI_ROUTES_PREFIX=payment

# Başarı/başarısızlık URL'leri
TAMI_SUCCESS_URL=/odeme/basarili
TAMI_FAILURE_URL=/odeme/basarisiz

Güvenlik Notları

Paket, Tami'ye gönderilen request body için securityHash değerini Tami PHP örneğiyle uyumlu JWK/HS512 JWT algoritmasıyla üretir. securityHash, request body'ye eklenmeden önceki JSON üzerinden hesaplanır.

Normal API response'larında dönen securityHash için Tami PHP örneklerinde doğrulama algoritması bulunmadığı için bu paket o alanı yanlış algoritmayla doğrulamaya çalışmaz. TAMI_RESPONSE_HASH_ENABLED=true yapılırsa paket fail-closed davranır ve TamiSecurityException fırlatır. Bu ayarı ancak normal API response hash algoritması netleşip pakette ayrıca implemente edildikten sonra açın.

3DS callback payload'ında hashedData varsa paket bu değeri secretKey ile HMAC-SHA256 kullanarak doğrular. Callback payload'ına güvenip siparişi doğrudan tamamlamayın; paket callback sonrası server-to-server /payment/complete-3ds çağrısı yapar.

Test

# Docker ile (önerilen)
make test

# veya doğrudan
docker compose run --rm php vendor/bin/phpunit

3DS Callback ve CSRF

3DS callback route'u varsayılan olarak api middleware ile kaydedilir — banka callback'i CSRF token taşımadığı için web middleware altında 419 hatası alabilir. Eğer web middleware kullanmak isterseniz VerifyCsrfToken middleware'ine tami/callback yolunu ekleyin:

// app/Http/Middleware/VerifyCsrfToken.php
protected $except = [
    'tami/callback',
];

Lisans

MIT

统计信息

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

GitHub 信息

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

其他信息

  • 授权协议: MIT
  • 更新时间: 2026-05-19

承接程序开发

PHP开发

VUE

Vue开发

前端开发

小程序开发

公众号开发

系统定制

数据库设计

云部署

网站建设

安全加固