Plugin Directory

Changeset 3452113


Ignore:
Timestamp:
02/02/2026 01:18:43 PM (8 weeks ago)
Author:
brksoft
Message:

2.2.0 version upload

Location:
hepsiburada-entegrasyon-brksoft/trunk
Files:
2 edited

Legend:

Unmodified
Added
Removed
  • hepsiburada-entegrasyon-brksoft/trunk/hepsiburada-entegrasyon-brksoft.php

    r3431798 r3452113  
    33 * Plugin Name: Hepsiburada Entegrasyon - Brksoft
    44 * Description: Hepsiburada ve WooCommerce arasında basit ürünler için stok senkronizasyonu.
    5  * Version: 2.0.0
     5 * Version: 2.2.0
    66 * Author: Brksoft
    77 * Author URI: https://brksoft.com/
     
    8383            .brkhi-error { background: #f8d7da; border-left: 4px solid #dc3545; padding: 15px; margin: 15px 0; }
    8484            .brkhi-info { background: #e7f3ff; border-left: 4px solid #0073aa; padding: 15px; margin: 15px 0; }
     85            .brkhi-log-table { width: 100%; border-collapse: collapse; margin-top: 15px; }
     86            .brkhi-log-table th, .brkhi-log-table td { padding: 10px; text-align: left; border-bottom: 1px solid #e0e0e0; font-size: 13px; }
     87            .brkhi-log-table th { background: #f8f9fa; font-weight: 600; }
     88            .brkhi-log-table tr:hover { background: #f8f9fa; }
     89            .brkhi-log-success { color: #28a745; }
     90            .brkhi-log-error { color: #dc3545; }
     91            .brkhi-log-info { color: #0073aa; }
     92            .brkhi-bulk-btn { margin-right: 10px; }
     93            .brkhi-spinner { display: none; margin-left: 10px; }
     94            .brkhi-bulk-result { margin-top: 15px; padding: 15px; display: none; }
     95            .brkhi-analysis-table { width: 100%; border-collapse: collapse; margin-top: 15px; }
     96            .brkhi-analysis-table th, .brkhi-analysis-table td { padding: 8px 12px; text-align: left; border-bottom: 1px solid #e0e0e0; font-size: 13px; }
     97            .brkhi-analysis-table th { background: #f8f9fa; font-weight: 600; }
     98            .brkhi-analysis-table tr:hover { background: #f8f9fa; }
     99            .brkhi-badge { display: inline-block; padding: 3px 8px; border-radius: 3px; font-size: 11px; font-weight: 600; }
     100            .brkhi-badge-success { background: #d4edda; color: #155724; }
     101            .brkhi-badge-warning { background: #fff3cd; color: #856404; }
     102            .brkhi-badge-error { background: #f8d7da; color: #721c24; }
     103            .brkhi-badge-pro { background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); color: #fff; cursor: pointer; transition: transform 0.2s, box-shadow 0.2s; }
     104            .brkhi-badge-pro:hover { transform: scale(1.05); box-shadow: 0 2px 8px rgba(102,126,234,0.4); }
     105            .brkhi-analysis-summary { display: flex; gap: 20px; margin: 15px 0; flex-wrap: wrap; }
     106            .brkhi-summary-card { background: #f8f9fa; padding: 15px 20px; border-radius: 6px; text-align: center; min-width: 120px; }
     107            .brkhi-summary-card .number { font-size: 24px; font-weight: 700; color: #333; }
     108            .brkhi-summary-card .label { font-size: 12px; color: #666; margin-top: 5px; }
     109            #brkhi-analysis-result { display: none; margin-top: 20px; }
    85110        </style>
    86111       
     
    95120        <?php if (isset($_GET['settings-updated'])): ?>
    96121            <div class="notice notice-success is-dismissible"><p><?php esc_html_e('Ayarlar kaydedildi!', 'hepsiburada-entegrasyon-brksoft'); ?></p></div>
     122        <?php endif; ?>
     123
     124        <?php if (isset($_GET['logs_cleared'])): ?>
     125            <div class="notice notice-success is-dismissible"><p><?php esc_html_e('İşlem geçmişi temizlendi.', 'hepsiburada-entegrasyon-brksoft'); ?></p></div>
    97126        <?php endif; ?>
    98127       
     
    201230            </ol>
    202231        </div>
    203        
     232
     233        <!-- Ürün Eşleştirme Analizi -->
     234        <?php if (!empty($merchant_id) && !empty($api_secret)): ?>
     235        <div class="brkhi-box">
     236            <h2>🔍 <?php esc_html_e('Ürün Eşleştirme Analizi', 'hepsiburada-entegrasyon-brksoft'); ?></h2>
     237
     238            <p><?php esc_html_e('WooCommerce ürünlerinizi Hepsiburada ile karşılaştırın ve eşleşme durumunu görün.', 'hepsiburada-entegrasyon-brksoft'); ?></p>
     239
     240            <p>
     241                <button type="button" id="brkhi-analyze" class="button button-secondary">
     242                    🔍 <?php esc_html_e('Ürünleri Analiz Et', 'hepsiburada-entegrasyon-brksoft'); ?>
     243                </button>
     244                <span class="spinner brkhi-spinner" id="brkhi-analyze-spinner"></span>
     245            </p>
     246
     247            <div id="brkhi-analysis-result"></div>
     248        </div>
     249        <?php endif; ?>
     250
     251        <!-- Toplu Stok Güncelleme -->
     252        <?php if (!empty($merchant_id) && !empty($api_secret)): ?>
     253        <div class="brkhi-box">
     254            <h2>🔄 <?php esc_html_e('Toplu Stok Güncelleme', 'hepsiburada-entegrasyon-brksoft'); ?></h2>
     255
     256            <p><?php esc_html_e('Tüm basit ürünlerin stoklarını Hepsiburada\'ya göndermek için butona tıklayın.', 'hepsiburada-entegrasyon-brksoft'); ?></p>
     257
     258            <div class="brkhi-warning">
     259                <strong>⚠️ <?php esc_html_e('Not:', 'hepsiburada-entegrasyon-brksoft'); ?></strong>
     260                <?php esc_html_e('Sadece SKU\'su olan ve stok takibi aktif basit ürünler gönderilir.', 'hepsiburada-entegrasyon-brksoft'); ?>
     261            </div>
     262
     263            <p>
     264                <button type="button" id="brkhi-bulk-sync" class="button button-primary brkhi-bulk-btn">
     265                    🚀 <?php esc_html_e('Tüm Stokları Gönder', 'hepsiburada-entegrasyon-brksoft'); ?>
     266                </button>
     267                <span class="spinner brkhi-spinner"></span>
     268            </p>
     269
     270            <div id="brkhi-bulk-result" class="brkhi-bulk-result"></div>
     271        </div>
     272        <?php endif; ?>
     273
     274        <!-- İşlem Geçmişi -->
     275        <div class="brkhi-box">
     276            <h2>📋 <?php esc_html_e('İşlem Geçmişi', 'hepsiburada-entegrasyon-brksoft'); ?></h2>
     277
     278            <?php
     279            $logs = get_option('brkhi_activity_logs', []);
     280            if (!empty($logs)):
     281                $logs = array_reverse($logs); // En yeni en üstte
     282            ?>
     283                <table class="brkhi-log-table">
     284                    <thead>
     285                        <tr>
     286                            <th><?php esc_html_e('Tarih', 'hepsiburada-entegrasyon-brksoft'); ?></th>
     287                            <th><?php esc_html_e('İşlem', 'hepsiburada-entegrasyon-brksoft'); ?></th>
     288                            <th><?php esc_html_e('Detay', 'hepsiburada-entegrasyon-brksoft'); ?></th>
     289                            <th><?php esc_html_e('Durum', 'hepsiburada-entegrasyon-brksoft'); ?></th>
     290                        </tr>
     291                    </thead>
     292                    <tbody>
     293                        <?php foreach ($logs as $log): ?>
     294                        <tr>
     295                            <td><?php echo esc_html($log['date']); ?></td>
     296                            <td><?php echo esc_html($log['action']); ?></td>
     297                            <td><?php echo esc_html($log['detail']); ?></td>
     298                            <td class="brkhi-log-<?php echo esc_attr($log['status']); ?>">
     299                                <?php
     300                                switch ($log['status']) {
     301                                    case 'success':
     302                                        echo '✅ ' . esc_html__('Başarılı', 'hepsiburada-entegrasyon-brksoft');
     303                                        break;
     304                                    case 'error':
     305                                        echo '❌ ' . esc_html__('Hata', 'hepsiburada-entegrasyon-brksoft');
     306                                        break;
     307                                    default:
     308                                        echo 'ℹ️ ' . esc_html__('Bilgi', 'hepsiburada-entegrasyon-brksoft');
     309                                }
     310                                ?>
     311                            </td>
     312                        </tr>
     313                        <?php endforeach; ?>
     314                    </tbody>
     315                </table>
     316
     317                <p style="margin-top: 15px;">
     318                    <a href="<?php echo esc_url(wp_nonce_url(admin_url('admin.php?page=brkhi_settings&brkhi_clear_logs=1'), 'brkhi_clear_logs')); ?>"
     319                       class="button" onclick="return confirm('<?php esc_attr_e('Tüm loglar silinecek. Emin misiniz?', 'hepsiburada-entegrasyon-brksoft'); ?>');">
     320                        🗑️ <?php esc_html_e('Logları Temizle', 'hepsiburada-entegrasyon-brksoft'); ?>
     321                    </a>
     322                </p>
     323            <?php else: ?>
     324                <p class="description"><?php esc_html_e('Henüz işlem kaydı bulunmuyor.', 'hepsiburada-entegrasyon-brksoft'); ?></p>
     325            <?php endif; ?>
     326        </div>
     327
    204328        <!-- Destek -->
    205329        <div class="brkhi-box">
    206330            <h2>💬 <?php esc_html_e('Destek', 'hepsiburada-entegrasyon-brksoft'); ?></h2>
    207331            <p>
    208                 <?php esc_html_e('Sorularınız için:', 'hepsiburada-entegrasyon-brksoft'); ?> 
     332                <?php esc_html_e('Sorularınız için:', 'hepsiburada-entegrasyon-brksoft'); ?>
    209333                <a href="https://brksoft.com/tr/iletisim/" target="_blank">brksoft.com/tr/iletisim</a>
    210334            </p>
    211             <p><strong><?php esc_html_e('Versiyon:', 'hepsiburada-entegrasyon-brksoft'); ?></strong> 2.0.0</p>
     335            <p><strong><?php esc_html_e('Versiyon:', 'hepsiburada-entegrasyon-brksoft'); ?></strong> 2.2.0</p>
    212336        </div>
     337
     338        <script>
     339        jQuery(document).ready(function($) {
     340            // Toplu Stok Güncelleme
     341            $('#brkhi-bulk-sync').on('click', function() {
     342                var $btn = $(this);
     343                var $spinner = $('.brkhi-spinner').not('#brkhi-analyze-spinner');
     344                var $result = $('#brkhi-bulk-result');
     345
     346                $btn.prop('disabled', true);
     347                $spinner.css('display', 'inline-block').addClass('is-active');
     348                $result.hide();
     349
     350                $.ajax({
     351                    url: ajaxurl,
     352                    type: 'POST',
     353                    data: {
     354                        action: 'brkhi_bulk_stock_sync',
     355                        nonce: '<?php echo wp_create_nonce('brkhi_bulk_sync'); ?>'
     356                    },
     357                    success: function(response) {
     358                        $spinner.hide().removeClass('is-active');
     359                        $btn.prop('disabled', false);
     360
     361                        if (response.success) {
     362                            $result.removeClass('brkhi-error').addClass('brkhi-success')
     363                                   .html('<strong>✅ ' + response.data.message + '</strong>').show();
     364                        } else {
     365                            $result.removeClass('brkhi-success').addClass('brkhi-error')
     366                                   .html('<strong>❌ ' + response.data.message + '</strong>').show();
     367                        }
     368
     369                        setTimeout(function() { location.reload(); }, 2000);
     370                    },
     371                    error: function() {
     372                        $spinner.hide().removeClass('is-active');
     373                        $btn.prop('disabled', false);
     374                        $result.removeClass('brkhi-success').addClass('brkhi-error')
     375                               .html('<strong>❌ <?php esc_html_e('Bağlantı hatası oluştu.', 'hepsiburada-entegrasyon-brksoft'); ?></strong>').show();
     376                    }
     377                });
     378            });
     379
     380            // Ürün Analizi
     381            $('#brkhi-analyze').on('click', function() {
     382                var $btn = $(this);
     383                var $spinner = $('#brkhi-analyze-spinner');
     384                var $result = $('#brkhi-analysis-result');
     385
     386                $btn.prop('disabled', true);
     387                $spinner.css('display', 'inline-block').addClass('is-active');
     388                $result.hide();
     389
     390                $.ajax({
     391                    url: ajaxurl,
     392                    type: 'POST',
     393                    data: {
     394                        action: 'brkhi_analyze_products',
     395                        nonce: '<?php echo wp_create_nonce('brkhi_analyze'); ?>'
     396                    },
     397                    success: function(response) {
     398                        $spinner.hide().removeClass('is-active');
     399                        $btn.prop('disabled', false);
     400
     401                        if (response.success) {
     402                            $result.html(response.data.html).show();
     403                        } else {
     404                            $result.html('<div class="brkhi-error"><strong>❌ ' + response.data.message + '</strong></div>').show();
     405                        }
     406                    },
     407                    error: function() {
     408                        $spinner.hide().removeClass('is-active');
     409                        $btn.prop('disabled', false);
     410                        $result.html('<div class="brkhi-error"><strong>❌ <?php esc_html_e('Bağlantı hatası oluştu.', 'hepsiburada-entegrasyon-brksoft'); ?></strong></div>').show();
     411                    }
     412                });
     413            });
     414        });
     415        </script>
    213416    </div>
    214417    <?php
     
    259462// SİPARİŞ GELDİĞİNDE HEPSİBURADA STOK GÜNCELLEME
    260463// =============================================================================
    261 add_action('woocommerce_thankyou', 'brkhi_update_hepsiburada_stock', 10, 1);
    262 add_action('woocommerce_order_status_processing', 'brkhi_update_hepsiburada_stock', 10, 1);
    263 add_action('woocommerce_order_status_completed', 'brkhi_update_hepsiburada_stock', 10, 1);
     464// woocommerce_reduce_order_stock: Stok düşürüldükten SONRA tetiklenir (en güvenilir)
     465add_action('woocommerce_reduce_order_stock', 'brkhi_update_hepsiburada_stock_after_reduce', 10, 1);
     466
     467function brkhi_update_hepsiburada_stock_after_reduce($order) {
     468    if (!$order) {
     469        return;
     470    }
     471
     472    // Order objesi veya ID olabilir
     473    if (is_numeric($order)) {
     474        $order = wc_get_order($order);
     475    }
     476
     477    if (!$order) {
     478        return;
     479    }
     480
     481    $order_id = $order->get_id();
     482    brkhi_update_hepsiburada_stock($order_id);
     483}
    264484
    265485function brkhi_update_hepsiburada_stock($order_id) {
     
    267487        return;
    268488    }
    269    
    270     // Çoklu tetiklenmeyi önle
    271     static $processed_orders = [];
    272     if (isset($processed_orders[$order_id])) {
    273         return;
    274     }
    275     $processed_orders[$order_id] = true;
    276489
    277490    // Siparişi al
     
    281494    }
    282495
     496    // Çoklu tetiklenmeyi önle (kalıcı - order meta ile)
     497    if ($order->get_meta('_brkhi_stock_synced')) {
     498        return;
     499    }
     500
     501    // Aynı request içinde de önle
     502    static $processed_orders = [];
     503    if (isset($processed_orders[$order_id])) {
     504        return;
     505    }
     506    $processed_orders[$order_id] = true;
     507
    283508    // Hepsiburada API kimlik bilgileri
    284509    $merchant_id = get_option('brkhi_merchantid_input', '');
     
    289514    }
    290515
    291     // API URL - PRODUCTION
    292     $url = "https://listing-external.hepsiburada.com/listings/merchantid/{$merchant_id}/stock-uploads";
    293 
    294     // Siparişteki tüm ürünleri al
    295     $products = [];
    296    
     516    $auth_header = base64_encode("{$merchant_id}:{$api_secret}");
     517    $api_headers = [
     518        'Authorization' => 'Basic ' . $auth_header,
     519        'User-Agent' => 'brksoft_dev',
     520        'Accept' => 'application/json',
     521        'Content-Type' => 'application/json',
     522    ];
     523
     524    // Siparişteki SKU'ları topla (product_id ile birlikte)
     525    $sku_stock_map = [];
     526
    297527    foreach ($order->get_items() as $item) {
    298528        $product = $item->get_product();
     
    302532            continue;
    303533        }
    304        
     534
    305535        $sku = $product->get_sku();
    306536        if (empty($sku)) {
    307537            continue;
    308538        }
    309        
     539
    310540        $current_stock = max(0, (int) $product->get_stock_quantity());
    311 
    312         $products[] = [
    313             'merchantSku' => $sku,
    314             'availableStock' => $current_stock,
     541        $sku_stock_map[$sku] = [
     542            'new_stock' => $current_stock,
     543            'product_id' => $product->get_id(),
    315544        ];
    316545    }
    317546
    318     // Gönderilecek ürün yoksa işlemi sonlandır
     547    if (empty($sku_stock_map)) {
     548        return;
     549    }
     550
     551    // Hepsiburada'dan listing bilgilerini çek (merchantSku -> hepsiburadaSku eşleşmesi için)
     552    $merchant_sku_list = implode(',', array_keys($sku_stock_map));
     553    $listing_url = "https://listing-external.hepsiburada.com/listings/merchantid/{$merchant_id}?merchantSkuList={$merchant_sku_list}&limit=100";
     554
     555    $listing_response = wp_remote_get($listing_url, [
     556        'timeout' => 30,
     557        'headers' => $api_headers,
     558    ]);
     559
     560    if (is_wp_error($listing_response)) {
     561        brkhi_log("Listing API hatası: " . $listing_response->get_error_message(), $order_id);
     562        return;
     563    }
     564
     565    $listing_code = wp_remote_retrieve_response_code($listing_response);
     566    if ($listing_code !== 200) {
     567        brkhi_log("Listing API HTTP hatası: {$listing_code}", $order_id);
     568        return;
     569    }
     570
     571    $listing_raw = wp_remote_retrieve_body($listing_response);
     572    $listing_body = json_decode($listing_raw, true);
     573
     574    // Debug: Raw response logla
     575    brkhi_log("Listing API response: " . substr($listing_raw, 0, 500), $order_id);
     576
     577    if (empty($listing_body['listings'])) {
     578        brkhi_log("Listing bulunamadı. SKU'lar: {$merchant_sku_list}", $order_id);
     579        return;
     580    }
     581
     582    // Stok güncelleme verisi oluştur (detaylı log için eski stok bilgisi ile)
     583    $products = [];
     584    $stock_changes = []; // Detaylı log için
     585    foreach ($listing_body['listings'] as $listing) {
     586        // API hem PascalCase hem camelCase dönebilir, ikisini de kontrol et
     587        $merchant_sku = $listing['MerchantSku'] ?? $listing['merchantSku'] ?? '';
     588        $hb_sku = $listing['HepsiburadaSku'] ?? $listing['hepsiburadaSku'] ?? '';
     589        $old_stock = $listing['AvailableStock'] ?? $listing['availableStock'] ?? 0;
     590
     591        brkhi_log("Listing parse: MerchantSku={$merchant_sku}, HepsiburadaSku={$hb_sku}", $order_id);
     592
     593        if (!empty($merchant_sku) && !empty($hb_sku) && isset($sku_stock_map[$merchant_sku])) {
     594            $sku_data = $sku_stock_map[$merchant_sku];
     595            $new_stock = $sku_data['new_stock'];
     596            $product_id = $sku_data['product_id'];
     597
     598            $products[] = [
     599                'hepsiburadaSku' => $hb_sku,
     600                'merchantSku' => $merchant_sku,
     601                'availableStock' => $new_stock,
     602            ];
     603
     604            // Detaylı log için stok değişim bilgisi kaydet
     605            $stock_changes[] = "{$merchant_sku} (ID:{$product_id}): {$old_stock}→{$new_stock}";
     606        }
     607    }
     608
    319609    if (empty($products)) {
    320         return;
    321     }
    322 
    323     // Authorization için Base64 kodlaması
    324     $auth_header = base64_encode("{$merchant_id}:{$api_secret}");
    325 
    326     // Hepsiburada API'ye stok güncelleme isteği gönder
    327     wp_remote_post($url, [
     610        brkhi_log("Eşleşen ürün bulunamadı. SKU map: " . wp_json_encode($sku_stock_map), $order_id);
     611        return;
     612    }
     613
     614    // Stok güncelleme isteği gönder
     615    $stock_url = "https://listing-external.hepsiburada.com/listings/merchantid/{$merchant_id}/stock-uploads";
     616    $stock_body_json = wp_json_encode($products);
     617
     618    brkhi_log("Stok güncelleme isteği: " . $stock_body_json, $order_id);
     619
     620    $stock_response = wp_remote_post($stock_url, [
    328621        'timeout' => 30,
    329         'headers' => [
    330             'Authorization' => 'Basic ' . $auth_header,
    331             'User-Agent' => 'brksoft_dev',
    332             'Accept' => 'application/json',
    333             'Content-Type' => 'application/json',
    334         ],
    335         'body' => wp_json_encode($products),
     622        'headers' => $api_headers,
     623        'body' => $stock_body_json,
    336624    ]);
     625
     626    if (is_wp_error($stock_response)) {
     627        brkhi_log("Stok API hatası: " . $stock_response->get_error_message(), $order_id);
     628        return;
     629    }
     630
     631    $stock_code = wp_remote_retrieve_response_code($stock_response);
     632    $stock_body = wp_remote_retrieve_body($stock_response);
     633
     634    if ($stock_code >= 200 && $stock_code < 300) {
     635        // Başarılı - tekrar tetiklenmemesi için işaretle
     636        $order->update_meta_data('_brkhi_stock_synced', current_time('timestamp'));
     637        $order->save();
     638
     639        brkhi_log("Stok güncelleme başarılı. Ürün sayısı: " . count($products), $order_id);
     640
     641        // Detaylı log: Sipariş #817 | FCC (ID:123): 9→8, ABC (ID:456): 5→4
     642        $stock_changes_str = implode(', ', $stock_changes);
     643        brkhi_add_log(
     644            __('Sipariş Stok Sync', 'hepsiburada-entegrasyon-brksoft'),
     645            sprintf(__('Sipariş #%d | %s', 'hepsiburada-entegrasyon-brksoft'), $order_id, $stock_changes_str),
     646            'success'
     647        );
     648    } else {
     649        brkhi_log("Stok güncelleme hatası (HTTP {$stock_code}): {$stock_body}", $order_id);
     650        brkhi_add_log(
     651            __('Sipariş Stok Sync', 'hepsiburada-entegrasyon-brksoft'),
     652            sprintf(__('Sipariş #%d - Hata: HTTP %d', 'hepsiburada-entegrasyon-brksoft'), $order_id, $stock_code),
     653            'error'
     654        );
     655    }
     656}
     657
     658/**
     659 * Aktivite log kaydetme fonksiyonu
     660 */
     661function brkhi_add_log($action, $detail, $status = 'info') {
     662    $logs = get_option('brkhi_activity_logs', []);
     663
     664    // Max 50 log tut
     665    if (count($logs) >= 50) {
     666        array_shift($logs);
     667    }
     668
     669    $logs[] = [
     670        'date' => current_time('d.m.Y H:i'),
     671        'action' => $action,
     672        'detail' => $detail,
     673        'status' => $status, // success, error, info
     674    ];
     675
     676    update_option('brkhi_activity_logs', $logs);
     677}
     678
     679/**
     680 * Debug log fonksiyonu
     681 */
     682function brkhi_log($message, $order_id = null) {
     683    if (defined('WP_DEBUG') && WP_DEBUG) {
     684        $prefix = '[Hepsiburada]';
     685        if ($order_id) {
     686            $prefix .= " [Sipariş #{$order_id}]";
     687        }
     688        error_log("{$prefix} {$message}");
     689    }
    337690}
    338691
     
    347700    return $links;
    348701}
     702
     703// =============================================================================
     704// LOG TEMİZLEME
     705// =============================================================================
     706add_action('admin_init', 'brkhi_handle_clear_logs');
     707function brkhi_handle_clear_logs() {
     708    if (isset($_GET['brkhi_clear_logs']) && $_GET['brkhi_clear_logs'] === '1') {
     709        if (!wp_verify_nonce($_GET['_wpnonce'], 'brkhi_clear_logs')) {
     710            wp_die(__('Güvenlik doğrulaması başarısız.', 'hepsiburada-entegrasyon-brksoft'));
     711        }
     712
     713        if (!current_user_can('manage_woocommerce')) {
     714            wp_die(__('Bu işlem için yetkiniz yok.', 'hepsiburada-entegrasyon-brksoft'));
     715        }
     716
     717        delete_option('brkhi_activity_logs');
     718        wp_redirect(admin_url('admin.php?page=brkhi_settings&logs_cleared=1'));
     719        exit;
     720    }
     721}
     722
     723// =============================================================================
     724// TOPLU STOK GÜNCELLEME AJAX
     725// =============================================================================
     726add_action('wp_ajax_brkhi_bulk_stock_sync', 'brkhi_bulk_stock_sync_handler');
     727function brkhi_bulk_stock_sync_handler() {
     728    // Nonce kontrolü
     729    if (!wp_verify_nonce($_POST['nonce'], 'brkhi_bulk_sync')) {
     730        wp_send_json_error(['message' => __('Güvenlik doğrulaması başarısız.', 'hepsiburada-entegrasyon-brksoft')]);
     731    }
     732
     733    // Yetki kontrolü
     734    if (!current_user_can('manage_woocommerce')) {
     735        wp_send_json_error(['message' => __('Bu işlem için yetkiniz yok.', 'hepsiburada-entegrasyon-brksoft')]);
     736    }
     737
     738    // API bilgileri
     739    $merchant_id = get_option('brkhi_merchantid_input', '');
     740    $api_secret = get_option('brkhi_apisecret_input', '');
     741
     742    if (empty($merchant_id) || empty($api_secret)) {
     743        wp_send_json_error(['message' => __('API bilgileri eksik.', 'hepsiburada-entegrasyon-brksoft')]);
     744    }
     745
     746    // Tüm basit ürünleri çek (stok takibi aktif ve SKU'su olanlar)
     747    $args = [
     748        'status' => 'publish',
     749        'type' => 'simple',
     750        'limit' => -1,
     751        'manage_stock' => true,
     752    ];
     753
     754    $products = wc_get_products($args);
     755    $sku_stock_map = [];
     756
     757    foreach ($products as $product) {
     758        $sku = $product->get_sku();
     759        if (empty($sku)) {
     760            continue;
     761        }
     762
     763        $stock = max(0, (int) $product->get_stock_quantity());
     764        $sku_stock_map[$sku] = $stock;
     765    }
     766
     767    if (empty($sku_stock_map)) {
     768        brkhi_add_log(
     769            __('Toplu Stok Sync', 'hepsiburada-entegrasyon-brksoft'),
     770            __('Gönderilecek ürün bulunamadı', 'hepsiburada-entegrasyon-brksoft'),
     771            'info'
     772        );
     773        wp_send_json_error(['message' => __('Stok takibi aktif ve SKU\'su olan basit ürün bulunamadı.', 'hepsiburada-entegrasyon-brksoft')]);
     774    }
     775
     776    $auth_header = base64_encode("{$merchant_id}:{$api_secret}");
     777    $api_headers = [
     778        'Authorization' => 'Basic ' . $auth_header,
     779        'User-Agent' => 'brksoft_dev',
     780        'Accept' => 'application/json',
     781        'Content-Type' => 'application/json',
     782    ];
     783
     784    // Hepsiburada'dan listing bilgilerini çek
     785    // SKU'ları 50'lik gruplar halinde gönder (URL uzunluk limiti için)
     786    $all_products = [];
     787    $sku_chunks = array_chunk(array_keys($sku_stock_map), 50);
     788
     789    foreach ($sku_chunks as $sku_chunk) {
     790        $merchant_sku_list = implode(',', $sku_chunk);
     791        $listing_url = "https://listing-external.hepsiburada.com/listings/merchantid/{$merchant_id}?merchantSkuList={$merchant_sku_list}&limit=100";
     792
     793        $listing_response = wp_remote_get($listing_url, [
     794            'timeout' => 60,
     795            'headers' => $api_headers,
     796        ]);
     797
     798        if (is_wp_error($listing_response)) {
     799            continue;
     800        }
     801
     802        $listing_code = wp_remote_retrieve_response_code($listing_response);
     803        if ($listing_code !== 200) {
     804            continue;
     805        }
     806
     807        $listing_body = json_decode(wp_remote_retrieve_body($listing_response), true);
     808        if (empty($listing_body['listings'])) {
     809            continue;
     810        }
     811
     812        foreach ($listing_body['listings'] as $listing) {
     813            // API hem PascalCase hem camelCase dönebilir
     814            $merchant_sku = $listing['MerchantSku'] ?? $listing['merchantSku'] ?? '';
     815            $hb_sku = $listing['HepsiburadaSku'] ?? $listing['hepsiburadaSku'] ?? '';
     816
     817            if (!empty($merchant_sku) && !empty($hb_sku) && isset($sku_stock_map[$merchant_sku])) {
     818                $all_products[] = [
     819                    'hepsiburadaSku' => $hb_sku,
     820                    'merchantSku' => $merchant_sku,
     821                    'availableStock' => $sku_stock_map[$merchant_sku],
     822                ];
     823            }
     824        }
     825    }
     826
     827    if (empty($all_products)) {
     828        brkhi_add_log(
     829            __('Toplu Stok Sync', 'hepsiburada-entegrasyon-brksoft'),
     830            __('HB\'da eşleşen ürün bulunamadı', 'hepsiburada-entegrasyon-brksoft'),
     831            'error'
     832        );
     833        wp_send_json_error(['message' => __('Hepsiburada\'da eşleşen ürün bulunamadı. SKU\'ların aynı olduğundan emin olun.', 'hepsiburada-entegrasyon-brksoft')]);
     834    }
     835
     836    // Stok güncelleme isteği gönder (max 4000 ürün - API limiti)
     837    $stock_url = "https://listing-external.hepsiburada.com/listings/merchantid/{$merchant_id}/stock-uploads";
     838    $product_chunks = array_chunk($all_products, 4000);
     839    $total_updated = 0;
     840    $has_error = false;
     841
     842    foreach ($product_chunks as $chunk) {
     843        $stock_response = wp_remote_post($stock_url, [
     844            'timeout' => 120,
     845            'headers' => $api_headers,
     846            'body' => wp_json_encode($chunk),
     847        ]);
     848
     849        if (is_wp_error($stock_response)) {
     850            $has_error = true;
     851            continue;
     852        }
     853
     854        $stock_code = wp_remote_retrieve_response_code($stock_response);
     855        if ($stock_code >= 200 && $stock_code < 300) {
     856            $total_updated += count($chunk);
     857        } else {
     858            $has_error = true;
     859        }
     860    }
     861
     862    if ($total_updated > 0) {
     863        brkhi_add_log(
     864            __('Toplu Stok Sync', 'hepsiburada-entegrasyon-brksoft'),
     865            sprintf(__('%d ürün stoku güncellendi', 'hepsiburada-entegrasyon-brksoft'), $total_updated),
     866            $has_error ? 'info' : 'success'
     867        );
     868
     869        wp_send_json_success([
     870            'message' => sprintf(
     871                __('%d ürün stoku Hepsiburada\'ya gönderildi.', 'hepsiburada-entegrasyon-brksoft'),
     872                $total_updated
     873            )
     874        ]);
     875    } else {
     876        brkhi_add_log(
     877            __('Toplu Stok Sync', 'hepsiburada-entegrasyon-brksoft'),
     878            __('Stok güncellemesi başarısız', 'hepsiburada-entegrasyon-brksoft'),
     879            'error'
     880        );
     881        wp_send_json_error(['message' => __('Stok güncellemesi başarısız oldu.', 'hepsiburada-entegrasyon-brksoft')]);
     882    }
     883}
     884
     885// =============================================================================
     886// ÜRÜN EŞLEŞTİRME ANALİZİ AJAX
     887// =============================================================================
     888add_action('wp_ajax_brkhi_analyze_products', 'brkhi_analyze_products_handler');
     889function brkhi_analyze_products_handler() {
     890    // Nonce kontrolü
     891    if (!wp_verify_nonce($_POST['nonce'], 'brkhi_analyze')) {
     892        wp_send_json_error(['message' => __('Güvenlik doğrulaması başarısız.', 'hepsiburada-entegrasyon-brksoft')]);
     893    }
     894
     895    // Yetki kontrolü
     896    if (!current_user_can('manage_woocommerce')) {
     897        wp_send_json_error(['message' => __('Bu işlem için yetkiniz yok.', 'hepsiburada-entegrasyon-brksoft')]);
     898    }
     899
     900    // API bilgileri
     901    $merchant_id = get_option('brkhi_merchantid_input', '');
     902    $api_secret = get_option('brkhi_apisecret_input', '');
     903
     904    if (empty($merchant_id) || empty($api_secret)) {
     905        wp_send_json_error(['message' => __('API bilgileri eksik.', 'hepsiburada-entegrasyon-brksoft')]);
     906    }
     907
     908    // Tüm WooCommerce ürünlerini çek
     909    $all_products = wc_get_products([
     910        'status' => 'publish',
     911        'limit' => -1,
     912    ]);
     913
     914    if (empty($all_products)) {
     915        wp_send_json_error(['message' => __('WooCommerce\'de ürün bulunamadı.', 'hepsiburada-entegrasyon-brksoft')]);
     916    }
     917
     918    // Ürünleri kategorilere ayır
     919    $simple_products = [];
     920    $variable_products = [];
     921    $no_sku_products = [];
     922
     923    foreach ($all_products as $product) {
     924        $type = $product->get_type();
     925        $sku = $product->get_sku();
     926        $name = $product->get_name();
     927        $id = $product->get_id();
     928        $stock = $product->get_stock_quantity();
     929        $manage_stock = $product->get_manage_stock();
     930
     931        $product_data = [
     932            'id' => $id,
     933            'name' => $name,
     934            'sku' => $sku,
     935            'stock' => $stock,
     936            'manage_stock' => $manage_stock,
     937            'type' => $type,
     938        ];
     939
     940        if ($type === 'variable') {
     941            $variable_products[] = $product_data;
     942        } elseif (empty($sku)) {
     943            $no_sku_products[] = $product_data;
     944        } else {
     945            $simple_products[] = $product_data;
     946        }
     947    }
     948
     949    // Hepsiburada'dan listing bilgilerini çek
     950    $auth_header = base64_encode("{$merchant_id}:{$api_secret}");
     951    $api_headers = [
     952        'Authorization' => 'Basic ' . $auth_header,
     953        'User-Agent' => 'brksoft_dev',
     954        'Accept' => 'application/json',
     955    ];
     956
     957    // SKU'ları 50'lik gruplar halinde HB'den kontrol et
     958    $matched_products = [];
     959    $unmatched_products = [];
     960    $hb_sku_map = [];
     961
     962    if (!empty($simple_products)) {
     963        $sku_list = array_column($simple_products, 'sku');
     964        $sku_chunks = array_chunk($sku_list, 50);
     965
     966        foreach ($sku_chunks as $sku_chunk) {
     967            $merchant_sku_list = implode(',', $sku_chunk);
     968            $listing_url = "https://listing-external.hepsiburada.com/listings/merchantid/{$merchant_id}?merchantSkuList={$merchant_sku_list}&limit=100";
     969
     970            $response = wp_remote_get($listing_url, [
     971                'timeout' => 60,
     972                'headers' => $api_headers,
     973            ]);
     974
     975            if (!is_wp_error($response) && wp_remote_retrieve_response_code($response) === 200) {
     976                $body = json_decode(wp_remote_retrieve_body($response), true);
     977                if (!empty($body['listings'])) {
     978                    foreach ($body['listings'] as $listing) {
     979                        // API hem PascalCase hem camelCase dönebilir
     980                        $m_sku = $listing['MerchantSku'] ?? $listing['merchantSku'] ?? '';
     981                        $hb_sku_map[$m_sku] = [
     982                            'hbSku' => $listing['HepsiburadaSku'] ?? $listing['hepsiburadaSku'] ?? '',
     983                            'hbStock' => $listing['AvailableStock'] ?? $listing['availableStock'] ?? 0,
     984                            'hbPrice' => $listing['Price'] ?? $listing['price'] ?? 0,
     985                            'isSalable' => $listing['IsSalable'] ?? $listing['isSalable'] ?? false,
     986                        ];
     987                    }
     988                }
     989            }
     990        }
     991
     992        // Eşleşen ve eşleşmeyenleri ayır
     993        foreach ($simple_products as $product) {
     994            if (isset($hb_sku_map[$product['sku']])) {
     995                $product['hb'] = $hb_sku_map[$product['sku']];
     996                $matched_products[] = $product;
     997            } else {
     998                $unmatched_products[] = $product;
     999            }
     1000        }
     1001    }
     1002
     1003    // HTML çıktısı oluştur
     1004    $html = '<div class="brkhi-analysis-summary">';
     1005    $html .= '<div class="brkhi-summary-card"><div class="number" style="color:#28a745;">' . count($matched_products) . '</div><div class="label">' . esc_html__('Eşleşen', 'hepsiburada-entegrasyon-brksoft') . '</div></div>';
     1006    $html .= '<div class="brkhi-summary-card"><div class="number" style="color:#dc3545;">' . count($unmatched_products) . '</div><div class="label">' . esc_html__('Eşleşmeyen', 'hepsiburada-entegrasyon-brksoft') . '</div></div>';
     1007    $html .= '<div class="brkhi-summary-card"><div class="number" style="color:#856404;">' . count($no_sku_products) . '</div><div class="label">' . esc_html__('SKU Yok', 'hepsiburada-entegrasyon-brksoft') . '</div></div>';
     1008    $html .= '<div class="brkhi-summary-card"><div class="number" style="color:#7c3aed;">' . count($variable_products) . '</div><div class="label">' . esc_html__('Varyasyonlu', 'hepsiburada-entegrasyon-brksoft') . '</div></div>';
     1009    $html .= '</div>';
     1010
     1011    // Tablo
     1012    $html .= '<table class="brkhi-analysis-table">';
     1013    $html .= '<thead><tr>';
     1014    $html .= '<th>' . esc_html__('Ürün', 'hepsiburada-entegrasyon-brksoft') . '</th>';
     1015    $html .= '<th>' . esc_html__('SKU', 'hepsiburada-entegrasyon-brksoft') . '</th>';
     1016    $html .= '<th>' . esc_html__('WC Stok', 'hepsiburada-entegrasyon-brksoft') . '</th>';
     1017    $html .= '<th>' . esc_html__('HB Stok', 'hepsiburada-entegrasyon-brksoft') . '</th>';
     1018    $html .= '<th>' . esc_html__('Durum', 'hepsiburada-entegrasyon-brksoft') . '</th>';
     1019    $html .= '</tr></thead><tbody>';
     1020
     1021    // Eşleşen ürünler
     1022    foreach ($matched_products as $product) {
     1023        $html .= '<tr>';
     1024        $html .= '<td><a href="' . esc_url(get_edit_post_link($product['id'])) . '" target="_blank">' . esc_html($product['name']) . '</a></td>';
     1025        $html .= '<td><code>' . esc_html($product['sku']) . '</code></td>';
     1026        $html .= '<td>' . ($product['manage_stock'] ? intval($product['stock']) : '-') . '</td>';
     1027        $html .= '<td>' . intval($product['hb']['hbStock']) . '</td>';
     1028        $html .= '<td><span class="brkhi-badge brkhi-badge-success">✓ ' . esc_html__('Eşleşti', 'hepsiburada-entegrasyon-brksoft') . '</span></td>';
     1029        $html .= '</tr>';
     1030    }
     1031
     1032    // Eşleşmeyen ürünler
     1033    foreach ($unmatched_products as $product) {
     1034        $html .= '<tr>';
     1035        $html .= '<td><a href="' . esc_url(get_edit_post_link($product['id'])) . '" target="_blank">' . esc_html($product['name']) . '</a></td>';
     1036        $html .= '<td><code>' . esc_html($product['sku']) . '</code></td>';
     1037        $html .= '<td>' . ($product['manage_stock'] ? intval($product['stock']) : '-') . '</td>';
     1038        $html .= '<td>-</td>';
     1039        $html .= '<td><span class="brkhi-badge brkhi-badge-error">✗ ' . esc_html__('Bulunamadı', 'hepsiburada-entegrasyon-brksoft') . '</span></td>';
     1040        $html .= '</tr>';
     1041    }
     1042
     1043    // SKU'su olmayan ürünler
     1044    foreach ($no_sku_products as $product) {
     1045        $html .= '<tr>';
     1046        $html .= '<td><a href="' . esc_url(get_edit_post_link($product['id'])) . '" target="_blank">' . esc_html($product['name']) . '</a></td>';
     1047        $html .= '<td><em style="color:#999;">' . esc_html__('SKU yok', 'hepsiburada-entegrasyon-brksoft') . '</em></td>';
     1048        $html .= '<td>' . ($product['manage_stock'] ? intval($product['stock']) : '-') . '</td>';
     1049        $html .= '<td>-</td>';
     1050        $html .= '<td><span class="brkhi-badge brkhi-badge-warning">⚠ ' . esc_html__('SKU Gerekli', 'hepsiburada-entegrasyon-brksoft') . '</span></td>';
     1051        $html .= '</tr>';
     1052    }
     1053
     1054    // Varyasyonlu ürünler
     1055    foreach ($variable_products as $product) {
     1056        $html .= '<tr>';
     1057        $html .= '<td><a href="' . esc_url(get_edit_post_link($product['id'])) . '" target="_blank">' . esc_html($product['name']) . '</a></td>';
     1058        $html .= '<td><em style="color:#999;">' . esc_html__('Varyasyonlu', 'hepsiburada-entegrasyon-brksoft') . '</em></td>';
     1059        $html .= '<td>-</td>';
     1060        $html .= '<td>-</td>';
     1061        $html .= '<td><a href="https://brksoft.com/tr/urun/hepsiburada-entegrasyonu-premium/" target="_blank" style="text-decoration:none;"><span class="brkhi-badge brkhi-badge-pro" style="cursor:pointer;">👑 ' . esc_html__('Pro Gerekli', 'hepsiburada-entegrasyon-brksoft') . '</span></a></td>';
     1062        $html .= '</tr>';
     1063    }
     1064
     1065    $html .= '</tbody></table>';
     1066
     1067    // Pro tanıtımı
     1068    if (!empty($variable_products)) {
     1069        $html .= '<div class="brkhi-info" style="margin-top:20px;">';
     1070        $html .= '<strong>👑 ' . esc_html__('Varyasyonlu Ürün Desteği', 'hepsiburada-entegrasyon-brksoft') . '</strong><br>';
     1071        $html .= esc_html__('Varyasyonlu ürünlerinizi senkronize etmek için Premium sürüme yükseltin.', 'hepsiburada-entegrasyon-brksoft') . ' ';
     1072        $html .= '<a href="https://brksoft.com/tr/urun/hepsiburada-entegrasyonu-premium/" target="_blank" style="color:#7c3aed;font-weight:bold;">';
     1073        $html .= esc_html__('Premium Satın Al', 'hepsiburada-entegrasyon-brksoft') . ' →</a>';
     1074        $html .= '</div>';
     1075    }
     1076
     1077    wp_send_json_success(['html' => $html]);
     1078}
  • hepsiburada-entegrasyon-brksoft/trunk/readme.txt

    r3431800 r3452113  
    66WC requires at least: 4.0
    77WC tested up to: 9.4
    8 Stable tag: 2.0.0
     8Stable tag: 2.2.0
    99Requires PHP: 7.4
    1010License: GPL-2.0+
     
    158158== 📝 Değişiklik Günlüğü ==
    159159
    160 = 2.0.0 - 2026-01-03 =
     160= 2.2.0 - 2026-01-03 =
    161161🎉 **Büyük Güncelleme!**
    162162
Note: See TracChangeset for help on using the changeset viewer.