iyzico / iyzipay-woocommerce

iyzico woocommerce integration
GNU Lesser General Public License v3.0
18 stars 13 forks source link

Fiyat Yuvarlama İşleminde Hata ve Ödeme Sürecinin İlerlemesinin Engellenmesi #40

Closed fatihmert closed 1 week ago

fatihmert commented 3 weeks ago

Merhaba,

iyzico WooCommerce eklentisinde ödeme sürecinde bir fiyat yuvarlama sorunu tespit ettik. Bu durum, API’den aldığımız 5062 hata koduna neden olarak sürecin kesilmesine yol açıyor. Ödeme sürecinde basketItems[0].price, price, ve paidPrice alanlarının eşitlenmediği durumlarda hata oluşmaktadır.

Fiyat alanlarının aynı ondalık hassasiyete yuvarlanması çözüm sağlayabilir. Kodlar incelendiğinde, $order->get_total() iki ondalık basamağa yuvarlanıyor. Ancak bu işlem, sepette tek ürün olduğunda ve sepetteki çoklu ürünlerin toplam fiyatında tutarsızlıklara yol açıyor gibi görünüyor. Bu doğrultuda basketItems[0].price değeri de paidPrice ve price alanlarına uyumlu olacak şekilde yuvarlanmalı.

Örnek Log Çıktısı ve İlgili Kod Satırları

İlgili hata loglarına ve ilgili kod satırına aşağıdan ulaşabilirsiniz:

Tek Ürünlü Sepet İle Ödeme İşlemi Deneme Sonrası Log:

{
  "locale": "",
  "conversationId": 5005,
  "price": "33.14",
  "basketId": 5005,
  "paymentGroup": "PRODUCT",
  "buyer": {
    "id": "1",
    "name": "Fatih Mert",
    "surname": "Doğancan",
    "identityNumber": "11111111111",
    "email": "test...@gmail.com",
    "gsmNumber": "+90555...",
    "registrationDate": "2024-10-28 12:47:12",
    "lastLoginDate": "2024-10-28 12:47:12",
    "registrationAddress": "..",
    "city": "...",
    "country": "TR",
    "zipCode": "34460",
    "ip": "127.0.0.1"
  },
  "shippingAddress": {
    "address": ".",
    "zipCode": "34460",
    "contactName": "Fatih Mert Doğancan",
    "city": "...",
    "country": "TR"
  },
  "billingAddress": {
    "address": "..",
    "zipCode": "34460",
    "contactName": "Fatih Mert Doğancan",
    "city": "Sarıyer",
    "country": "TR"
  },
  "basketItems": [
    {
      "id": "3940",
      "price": "33.140338",
      "name": "Test Ürün - Prod",
      "category1": "14 Ayar Bileklik, 22 Ayar Set, Altın Tül, Bileklikler",
      "itemType": "PHYSICAL"
    }
  ],
  "callbackUrl": "https://example.com/odeme/siparis-alindi/5005/?key=wc_order_wy8ymrr3PBE5R&wc-api=iyzipay",
  "paymentSource": "WOOCOMMERCE|9.3.3|CARRERA-PWI-3.5.7",
  "currency": "TRY",
  "paidPrice": "33.14"
}

Not: Kişisel bilgilerimi Payload içerisinden kaldırdım.

API Response:

{
  status: 'failure',
  errorCode: '5062',
  errorMessage: 'Gönderilen tutar tüm kırılımların toplam tutarına eşit olmalıdır',
  locale: 'tr',
  systemTime: 1730124479427,
  conversationId: '5010'
}

WooCommerce Tarafında Oluşan Hata Mesajı:

Uncaught TypeError: Iyzico\IyzipayWoocommerce\Pwi\Pwi::redirect_to_iyzico(): Argument #1 ($paymentPageUrl) must be of type string, null given, called in /home/cyclechain.io/sarigelin/wp-content/plugins/iyzico-woocommerce/includes/Pwi/Pwi.php on line 86 and defined in /home/cyclechain.io/sarigelin/wp-content/plugins/iyzico-woocommerce/includes/Pwi/Pwi.php:151  
Ek bağlam
{
    "error": {
        "type": 1,
        "file": "/home/cyclechain.io/sarigelin/wp-content/plugins/iyzico-woocommerce/includes/Pwi/Pwi.php",
        "line": 151
    },
    "backtrace": [
        "",
        "#0 /home/cyclechain.io/sarigelin/wp-content/plugins/iyzico-woocommerce/includes/Pwi/Pwi.php(86): Iyzico\IyzipayWoocommerce\Pwi\Pwi->redirect_to_iyzico()",
        "#1 /home/cyclechain.io/sarigelin/wp-content/plugins/woocommerce/includes/class-wc-checkout.php(1062): Iyzico\IyzipayWoocommerce\Pwi\Pwi->process_payment()",
        "#2 /home/cyclechain.io/sarigelin/wp-content/plugins/woocommerce/includes/class-wc-checkout.php(1293): WC_Checkout->process_order_payment()",
        "#3 /home/cyclechain.io/sarigelin/wp-content/plugins/woocommerce/includes/class-wc-ajax.php(520): WC_Checkout->process_checkout()",
        "#4 /home/cyclechain.io/sarigelin/wp-includes/class-wp-hook.php(324): WC_AJAX::checkout()",
        "#5 /home/cyclechain.io/sarigelin/wp-includes/class-wp-hook.php(348): WP_Hook->apply_filters()",
        "#6 /home/cyclechain.io/sarigelin/wp-includes/plugin.php(517): WP_Hook->do_action()",
        "#7 /home/cyclechain.io/sarigelin/wp-content/plugins/woocommerce/includes/class-wc-ajax.php(96): do_action()",
        "#8 /home/cyclechain.io/sarigelin/wp-includes/class-wp-hook.php(324): WC_AJAX::do_wc_ajax()",
        "#9 /home/cyclechain.io/sarigelin/wp-includes/class-wp-hook.php(348): WP_Hook->apply_filters()",
        "#10 /home/cyclechain.io/sarigelin/wp-includes/plugin.php(517): WP_Hook->do_action()",
        "#11 /home/cyclechain.io/sarigelin/wp-includes/template-loader.php(13): do_action()",
        "#12 /home/cyclechain.io/sarigelin/wp-blog-header.php(19): require_once('...')",
        "#13 /home/cyclechain.io/sarigelin/index.php(17): require('...')",
        "#14 {main}",
        "thrown"
    ]
}

Çözüm Önerisi:

Eğer price ve paidPrice gibi alanların tümü aynı ondalık hassasiyete yuvarlanırsa ve sepette birden fazla ürün olduğunda fiyat eşleşmeleri kontrol edilirse bu hatanın önüne geçilebilir. basketItems[0].price değeri de price ve paidPrice ile aynı formatta yuvarlanarak gönderildiğinde istek başarılı olmaktadır.

{
  status: 'success',
  locale: 'tr',
  systemTime: 1730124983024,
  conversationId: '5005',
  token: '1fc37a3e----------a8c7dea39baa',
  checkoutFormContent: `<script>..</script>`,
  tokenExpireTime: 1800,
  paymentPageUrl: 'https://cpp.iyzipay.com?token=1fc37a3e-fe8d-4b5c-8445-a8c7dea39baa&lang=tr',
  payWithIyzicoPageUrl: 'https://ode.iyzico.com/?token=1fc37a3e-fe8d-4b5c-8445-a8c7dea39baa&lang=tr',
  signature: 'cb95a012c1ff....64e7071bc4110fbb'
}

Dip Not

Sepetteki birden fazla üründe de aynı davranış olabilir, emin olamadım. Request kısmını test edemedim ama aynı payload değerinde fiyatlar aynı olduğunda bile WooCommerce tarafında ödeme işlemi gerçekleşmiyor. Authorization key ile ilgili bir problem olabilir.

Örnek Request Kodu Guzzle
<?php

$apiKey = "";
$secretKey = "";

// İstek bilgileri
$baseUrl = "https://api.iyzipay.com";
$productId = 5010;
$uriPath = "/payment/iyzipos/checkoutform/initialize/auth/ecom";
$requestData = json_encode(json_decode(<<<EOF
...
EOF));

function generateAuthorizationString($apiKey, $secretKey, $uriPath, $requestData) {
    $randomKey = time() . "123456789";
    echo 'randomKey: ' . $randomKey . PHP_EOL;

    $payload = empty($requestData) ? $randomKey . $uriPath : $randomKey . $uriPath . $requestData;
    $encryptedData = hash_hmac('sha256', $payload, $secretKey);
    echo 'encryptedData: ' . $encryptedData . PHP_EOL;

    $authorizationString = "apiKey:$apiKey&randomKey:$randomKey&signature:$encryptedData";
    echo 'authorizationString: ' . $authorizationString . PHP_EOL;

    $base64EncodedAuthorization = base64_encode($authorizationString);
    echo 'base64EncodedAuthorization: ' . $base64EncodedAuthorization . PHP_EOL;

    return "IYZWSv2 " . $base64EncodedAuthorization;
}

$authorizationHeader = generateAuthorizationString($apiKey, $secretKey, $uriPath, $requestData);

$client = new Client();
try {
    $response = $client->post($baseUrl . $uriPath, [
        'headers' => [
            'Content-Type' => 'application/json',
            'Authorization' => $authorizationHeader,
        ],
        'json' => json_decode($requestData, true),
    ]);

    $responseBody = $response->getBody();
    echo ">>>: " . $responseBody . PHP_EOL;
} catch (RequestException $e) {
    echo "!!!: " . $e->getMessage() . PHP_EOL;
    if ($e->hasResponse()) {
        echo "!!!: " . $e->getResponse()->getBody() . PHP_EOL;
    }
}
?>
tarikkamat commented 2 weeks ago

Selamlar, 3.5.8 versiyonu çıkmıştır. Kontrol edebilirsiniz.

fatihmert commented 1 week ago

Selamlar, elinize sağlık.