Changeset 3452113
- Timestamp:
- 02/02/2026 01:18:43 PM (8 weeks ago)
- Location:
- hepsiburada-entegrasyon-brksoft/trunk
- Files:
-
- 2 edited
-
hepsiburada-entegrasyon-brksoft.php (modified) (10 diffs)
-
readme.txt (modified) (2 diffs)
Legend:
- Unmodified
- Added
- Removed
-
hepsiburada-entegrasyon-brksoft/trunk/hepsiburada-entegrasyon-brksoft.php
r3431798 r3452113 3 3 * Plugin Name: Hepsiburada Entegrasyon - Brksoft 4 4 * Description: Hepsiburada ve WooCommerce arasında basit ürünler için stok senkronizasyonu. 5 * Version: 2. 0.05 * Version: 2.2.0 6 6 * Author: Brksoft 7 7 * Author URI: https://brksoft.com/ … … 83 83 .brkhi-error { background: #f8d7da; border-left: 4px solid #dc3545; padding: 15px; margin: 15px 0; } 84 84 .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; } 85 110 </style> 86 111 … … 95 120 <?php if (isset($_GET['settings-updated'])): ?> 96 121 <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> 97 126 <?php endif; ?> 98 127 … … 201 230 </ol> 202 231 </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 204 328 <!-- Destek --> 205 329 <div class="brkhi-box"> 206 330 <h2>💬 <?php esc_html_e('Destek', 'hepsiburada-entegrasyon-brksoft'); ?></h2> 207 331 <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'); ?> 209 333 <a href="https://brksoft.com/tr/iletisim/" target="_blank">brksoft.com/tr/iletisim</a> 210 334 </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> 212 336 </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> 213 416 </div> 214 417 <?php … … 259 462 // SİPARİŞ GELDİĞİNDE HEPSİBURADA STOK GÜNCELLEME 260 463 // ============================================================================= 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) 465 add_action('woocommerce_reduce_order_stock', 'brkhi_update_hepsiburada_stock_after_reduce', 10, 1); 466 467 function 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 } 264 484 265 485 function brkhi_update_hepsiburada_stock($order_id) { … … 267 487 return; 268 488 } 269 270 // Çoklu tetiklenmeyi önle271 static $processed_orders = [];272 if (isset($processed_orders[$order_id])) {273 return;274 }275 $processed_orders[$order_id] = true;276 489 277 490 // Siparişi al … … 281 494 } 282 495 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 283 508 // Hepsiburada API kimlik bilgileri 284 509 $merchant_id = get_option('brkhi_merchantid_input', ''); … … 289 514 } 290 515 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 297 527 foreach ($order->get_items() as $item) { 298 528 $product = $item->get_product(); … … 302 532 continue; 303 533 } 304 534 305 535 $sku = $product->get_sku(); 306 536 if (empty($sku)) { 307 537 continue; 308 538 } 309 539 310 540 $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(), 315 544 ]; 316 545 } 317 546 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 319 609 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, [ 328 621 '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, 336 624 ]); 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 */ 661 function 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 */ 682 function 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 } 337 690 } 338 691 … … 347 700 return $links; 348 701 } 702 703 // ============================================================================= 704 // LOG TEMİZLEME 705 // ============================================================================= 706 add_action('admin_init', 'brkhi_handle_clear_logs'); 707 function 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 // ============================================================================= 726 add_action('wp_ajax_brkhi_bulk_stock_sync', 'brkhi_bulk_stock_sync_handler'); 727 function 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 // ============================================================================= 888 add_action('wp_ajax_brkhi_analyze_products', 'brkhi_analyze_products_handler'); 889 function 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 6 6 WC requires at least: 4.0 7 7 WC tested up to: 9.4 8 Stable tag: 2. 0.08 Stable tag: 2.2.0 9 9 Requires PHP: 7.4 10 10 License: GPL-2.0+ … … 158 158 == 📝 Değişiklik Günlüğü == 159 159 160 = 2. 0.0 - 2026-01-03 =160 = 2.2.0 - 2026-01-03 = 161 161 🎉 **Büyük Güncelleme!** 162 162
Note: See TracChangeset
for help on using the changeset viewer.