Plugin Directory

Changeset 3493482


Ignore:
Timestamp:
03/28/2026 05:19:26 PM (5 days ago)
Author:
durasi
Message:

v6.2.0: Extended Cloud Sync Faz 2

Location:
api-isarud
Files:
10 deleted
4 edited
7 copied

Legend:

Unmodified
Added
Removed
  • api-isarud/tags/6.2.0/api-isarud.php

    r3493435 r3493482  
    1717if (!defined('ABSPATH')) exit;
    1818
    19 define('ISARUD_VERSION', '6.1.0');
     19define('ISARUD_VERSION', '6.2.0');
    2020define('ISARUD_DIR', plugin_dir_path(__FILE__));
    2121define('ISARUD_URL', plugin_dir_url(__FILE__));
  • api-isarud/tags/6.2.0/isarud-cloud-sync.php

    r3493435 r3493482  
    22/**
    33 * Isarud Cloud Sync — isarud.com API v2 entegrasyonu
    4  * WP Plugin v6.1.0
     4 * WP Plugin v6.2.0
    55 */
    66if (!defined('ABSPATH')) exit;
     
    1919        add_action('isarud_cloud_sync_hook', [$this, 'run_cloud_sync']);
    2020        add_action('woocommerce_new_order', [$this, 'sync_order_to_cloud'], 40, 1);
    21 
    2221        if (get_option('isarud_cloud_enabled') === 'yes') {
    2322            if (!wp_next_scheduled('isarud_cloud_sync_hook')) {
     
    2726    }
    2827
    29     private function get_cloud_key(): string {
    30         return get_option('isarud_cloud_api_key', '');
    31     }
    32 
    33     public function is_enabled(): bool {
    34         return get_option('isarud_cloud_enabled') === 'yes' && !empty($this->get_cloud_key());
    35     }
     28    private function get_cloud_key(): string { return get_option('isarud_cloud_api_key', ''); }
     29    public function is_enabled(): bool { return get_option('isarud_cloud_enabled') === 'yes' && !empty($this->get_cloud_key()); }
    3630
    3731    private function api_request(string $endpoint, array $data = [], string $method = 'POST'): array {
    3832        $key = $this->get_cloud_key();
    3933        if (empty($key)) return ['error' => 'Cloud API key not configured'];
    40 
    41         $args = [
    42             'method' => $method,
    43             'timeout' => 30,
    44             'headers' => [
    45                 'Content-Type' => 'application/json',
    46                 'X-Marketplace-Key' => $key,
    47                 'User-Agent' => 'IsarudWP/' . ISARUD_VERSION,
    48             ],
    49         ];
    50 
    51         if (!empty($data) && in_array($method, ['POST', 'PUT'])) {
    52             $args['body'] = wp_json_encode($data);
    53         }
    54 
     34        $args = ['method' => $method, 'timeout' => 30, 'headers' => ['Content-Type' => 'application/json', 'X-Marketplace-Key' => $key, 'User-Agent' => 'IsarudWP/' . ISARUD_VERSION]];
     35        if (!empty($data) && in_array($method, ['POST', 'PUT'])) $args['body'] = wp_json_encode($data);
    5536        $response = wp_remote_request($this->api_base . $endpoint, $args);
    56 
    57         if (is_wp_error($response)) {
    58             return ['error' => $response->get_error_message()];
    59         }
    60 
     37        if (is_wp_error($response)) return ['error' => $response->get_error_message()];
    6138        $code = wp_remote_retrieve_response_code($response);
    6239        $body = json_decode(wp_remote_retrieve_body($response), true) ?: [];
    63 
    64         if ($code >= 400) {
    65             return ['error' => $body['error'] ?? "HTTP {$code}"];
    66         }
    67 
     40        if ($code >= 400) return ['error' => $body['error'] ?? "HTTP {$code}"];
    6841        return $body;
    6942    }
    7043
    7144    public function connect_site(string $bearer_token): array {
    72         $response = wp_remote_post('https://isarud.com/api/v2/marketplace/connect', [
    73             'timeout' => 30,
    74             'headers' => [
    75                 'Content-Type' => 'application/json',
    76                 'Authorization' => 'Bearer ' . $bearer_token,
    77             ],
    78             'body' => wp_json_encode([
    79                 'platform' => 'wordpress',
    80                 'site_url' => home_url(),
    81                 'site_name' => get_bloginfo('name'),
    82             ]),
    83         ]);
    84 
    85         if (is_wp_error($response)) {
    86             return ['error' => $response->get_error_message()];
    87         }
    88 
     45        $response = wp_remote_post('https://isarud.com/api/v2/marketplace/connect', ['timeout' => 30, 'headers' => ['Content-Type' => 'application/json', 'Authorization' => 'Bearer ' . $bearer_token], 'body' => wp_json_encode(['platform' => 'wordpress', 'site_url' => home_url(), 'site_name' => get_bloginfo('name')])]);
     46        if (is_wp_error($response)) return ['error' => $response->get_error_message()];
    8947        $body = json_decode(wp_remote_retrieve_body($response), true) ?: [];
    90 
    9148        if (!empty($body['success']) && !empty($body['platform']['api_key'])) {
    9249            update_option('isarud_cloud_api_key', $body['platform']['api_key']);
     
    9653            return ['success' => true, 'message' => 'Connected to isarud.com'];
    9754        }
    98 
    99         if (isset($body['error']) && strpos($body['error'], 'already connected') !== false) {
    100             return ['success' => true, 'message' => 'Already connected'];
    101         }
    102 
     55        if (isset($body['error']) && strpos($body['error'], 'already connected') !== false) return ['success' => true, 'message' => 'Already connected'];
    10356        return ['error' => $body['error'] ?? 'Connection failed'];
    10457    }
    10558
    10659    public function sync_products(): array {
    107         if (!$this->is_enabled() || !class_exists('WooCommerce')) {
    108             return ['error' => 'Cloud sync not enabled or WooCommerce not active'];
    109         }
    110 
     60        if (!$this->is_enabled() || !class_exists('WooCommerce')) return ['error' => 'Cloud sync not enabled or WooCommerce not active'];
    11161        global $wpdb;
    112         $marketplaces = $wpdb->get_results(
    113             "SELECT marketplace FROM {$wpdb->prefix}isarud_credentials WHERE is_active=1"
    114         );
    115 
     62        $marketplaces = $wpdb->get_results("SELECT marketplace FROM {$wpdb->prefix}isarud_credentials WHERE is_active=1");
    11663        $products_data = [];
    11764        $wc_products = wc_get_products(['status' => 'publish', 'limit' => 500]);
    118 
    11965        foreach ($wc_products as $product) {
    120             $products_data[] = [
    121                 'external_id' => (string)$product->get_id(),
    122                 'marketplace' => 'woocommerce',
    123                 'title' => $product->get_name(),
    124                 'sku' => $product->get_sku(),
    125                 'price' => (float)$product->get_price(),
    126                 'stock' => $product->get_stock_quantity() ?? 0,
    127                 'status' => $product->get_status(),
    128                 'image_url' => wp_get_attachment_url($product->get_image_id()) ?: null,
    129                 'meta' => [
    130                     'barcode' => get_post_meta($product->get_id(), '_isarud_barcode', true),
    131                     'permalink' => $product->get_permalink(),
    132                 ],
    133             ];
    134 
     66            $products_data[] = ['external_id' => (string)$product->get_id(), 'marketplace' => 'woocommerce', 'title' => $product->get_name(), 'sku' => $product->get_sku(), 'price' => (float)$product->get_price(), 'stock' => $product->get_stock_quantity() ?? 0, 'status' => $product->get_status(), 'image_url' => wp_get_attachment_url($product->get_image_id()) ?: null, 'meta' => ['barcode' => get_post_meta($product->get_id(), '_isarud_barcode', true), 'permalink' => $product->get_permalink()]];
    13567            foreach ($marketplaces as $mp) {
    13668                $barcode = get_post_meta($product->get_id(), '_isarud_barcode', true) ?: $product->get_sku();
    13769                if (empty($barcode)) continue;
    138 
    139                 $products_data[] = [
    140                     'external_id' => $barcode,
    141                     'marketplace' => $mp->marketplace,
    142                     'title' => $product->get_name(),
    143                     'sku' => $product->get_sku(),
    144                     'price' => $this->apply_margin((float)$product->get_price(), $mp->marketplace),
    145                     'stock' => $product->get_stock_quantity() ?? 0,
    146                     'status' => $product->get_status(),
    147                     'image_url' => wp_get_attachment_url($product->get_image_id()) ?: null,
    148                 ];
     70                $products_data[] = ['external_id' => $barcode, 'marketplace' => $mp->marketplace, 'title' => $product->get_name(), 'sku' => $product->get_sku(), 'price' => $this->apply_margin((float)$product->get_price(), $mp->marketplace), 'stock' => $product->get_stock_quantity() ?? 0, 'status' => $product->get_status(), 'image_url' => wp_get_attachment_url($product->get_image_id()) ?: null];
    14971            }
    15072        }
    151 
    152         if (empty($products_data)) {
    153             return ['success' => true, 'synced' => 0, 'message' => 'No products to sync'];
    154         }
    155 
    156         $total_synced = 0;
    157         $total_failed = 0;
    158 
     73        if (empty($products_data)) return ['success' => true, 'synced' => 0, 'message' => 'No products to sync'];
     74        $total_synced = 0; $total_failed = 0;
    15975        foreach (array_chunk($products_data, 100) as $chunk) {
    16076            $result = $this->api_request('products/sync', ['products' => $chunk]);
    161             if (isset($result['error'])) {
    162                 $total_failed += count($chunk);
    163             } else {
    164                 $total_synced += $result['synced'] ?? 0;
    165                 $total_failed += $result['failed'] ?? 0;
    166             }
    167         }
    168 
     77            if (isset($result['error'])) $total_failed += count($chunk); else { $total_synced += $result['synced'] ?? 0; $total_failed += $result['failed'] ?? 0; }
     78        }
    16979        update_option('isarud_cloud_last_product_sync', current_time('mysql'));
    170 
    171         return [
    172             'success' => true,
    173             'synced' => $total_synced,
    174             'failed' => $total_failed,
    175         ];
     80        return ['success' => true, 'synced' => $total_synced, 'failed' => $total_failed];
    17681    }
    17782
    17883    public function sync_orders(): array {
    179         if (!$this->is_enabled() || !class_exists('WooCommerce')) {
    180             return ['error' => 'Cloud sync not enabled'];
    181         }
    182 
     84        if (!$this->is_enabled() || !class_exists('WooCommerce')) return ['error' => 'Cloud sync not enabled'];
    18385        $last_sync = get_option('isarud_cloud_last_order_sync', '2000-01-01 00:00:00');
    184 
    185         $orders = wc_get_orders([
    186             'date_created' => '>' . strtotime($last_sync),
    187             'limit' => 500,
    188             'orderby' => 'date',
    189             'order' => 'ASC',
    190         ]);
    191 
    192         if (empty($orders)) {
    193             return ['success' => true, 'synced' => 0, 'message' => 'No new orders'];
    194         }
    195 
     86        $orders = wc_get_orders(['date_created' => '>' . strtotime($last_sync), 'limit' => 500, 'orderby' => 'date', 'order' => 'ASC']);
     87        if (empty($orders)) return ['success' => true, 'synced' => 0, 'message' => 'No new orders'];
    19688        $orders_data = [];
    197         foreach ($orders as $order) {
    198             $orders_data[] = $this->format_order($order);
    199         }
    200 
    201         $total_synced = 0;
    202         $total_failed = 0;
    203 
     89        foreach ($orders as $order) $orders_data[] = $this->format_order($order);
     90        $total_synced = 0; $total_failed = 0;
    20491        foreach (array_chunk($orders_data, 100) as $chunk) {
    20592            $result = $this->api_request('orders/sync', ['orders' => $chunk]);
    206             if (isset($result['error'])) {
    207                 $total_failed += count($chunk);
    208             } else {
    209                 $total_synced += $result['synced'] ?? 0;
    210                 $total_failed += $result['failed'] ?? 0;
    211             }
    212         }
    213 
     93            if (isset($result['error'])) $total_failed += count($chunk); else { $total_synced += $result['synced'] ?? 0; $total_failed += $result['failed'] ?? 0; }
     94        }
    21495        update_option('isarud_cloud_last_order_sync', current_time('mysql'));
    215 
    216         return [
    217             'success' => true,
    218             'synced' => $total_synced,
    219             'failed' => $total_failed,
    220         ];
     96        return ['success' => true, 'synced' => $total_synced, 'failed' => $total_failed];
    22197    }
    22298
    22399    public function sync_order_to_cloud(int $order_id): void {
    224100        if (!$this->is_enabled()) return;
    225 
    226101        $order = wc_get_order($order_id);
    227102        if (!$order) return;
    228 
    229         $this->api_request('orders/sync', [
    230             'orders' => [$this->format_order($order)],
    231         ]);
     103        $this->api_request('orders/sync', ['orders' => [$this->format_order($order)]]);
    232104    }
    233105
    234106    private function format_order($order): array {
    235         return [
    236             'external_id' => (string)$order->get_id(),
    237             'marketplace' => 'woocommerce',
    238             'customer_name' => trim($order->get_billing_first_name() . ' ' . $order->get_billing_last_name()),
    239             'customer_email' => $order->get_billing_email(),
    240             'total' => (float)$order->get_total(),
    241             'currency' => $order->get_currency(),
    242             'status' => $order->get_status(),
    243             'order_date' => $order->get_date_created()?->format('Y-m-d H:i:s'),
    244             'meta' => [
    245                 'billing_country' => $order->get_billing_country(),
    246                 'shipping_country' => $order->get_shipping_country(),
    247                 'payment_method' => $order->get_payment_method(),
    248                 'items_count' => $order->get_item_count(),
    249             ],
    250         ];
    251     }
    252 
    253     /**
    254      * Sync extended data: settings, customers, abandoned carts, einvoices
    255      */
     107        return ['external_id' => (string)$order->get_id(), 'marketplace' => 'woocommerce', 'customer_name' => trim($order->get_billing_first_name() . ' ' . $order->get_billing_last_name()), 'customer_email' => $order->get_billing_email(), 'total' => (float)$order->get_total(), 'currency' => $order->get_currency(), 'status' => $order->get_status(), 'order_date' => $order->get_date_created()?->format('Y-m-d H:i:s'), 'meta' => ['billing_country' => $order->get_billing_country(), 'shipping_country' => $order->get_shipping_country(), 'payment_method' => $order->get_payment_method(), 'items_count' => $order->get_item_count()]];
     108    }
     109
    256110    public function sync_extended_data(): array {
    257         if (!$this->is_enabled()) {
    258             return ['error' => 'Cloud sync not enabled'];
    259         }
    260 
     111        if (!$this->is_enabled()) return ['error' => 'Cloud sync not enabled'];
    261112        $results = [];
    262 
    263113        $results['settings'] = $this->sync_settings();
    264114        $results['customers'] = $this->sync_customers();
    265115        $results['abandoned_carts'] = $this->sync_abandoned_carts();
    266116        $results['einvoices'] = $this->sync_einvoices();
    267 
     117        $results['credentials'] = $this->sync_credentials();
     118        $results['screening_logs'] = $this->sync_screening_logs();
     119        $results['sync_logs'] = $this->sync_sync_logs();
     120        $results['suppliers'] = $this->sync_suppliers();
     121        $results['affiliates'] = $this->sync_affiliates();
    268122        update_option('isarud_cloud_last_extended_sync', current_time('mysql'));
    269 
    270123        return $results;
    271124    }
    272125
    273126    private function sync_settings(): array {
    274         $option_keys = [
    275             'isarud_b2b_settings',
    276             'isarud_currency_settings',
    277             'isarud_tcmb_rates',
    278             'isarud_segment_settings',
    279             'isarud_einvoice_settings',
    280             'isarud_popup_settings',
    281             'isarud_popup_campaigns',
    282             'isarud_cart_recovery_settings',
    283             'isarud_email_marketing_settings',
    284             'isarud_email_log',
    285             'isarud_upsell_settings',
    286             'isarud_upsell_rules',
    287         ];
    288 
     127        $option_keys = ['isarud_b2b_settings', 'isarud_currency_settings', 'isarud_tcmb_rates', 'isarud_segment_settings', 'isarud_einvoice_settings', 'isarud_popup_settings', 'isarud_popup_campaigns', 'isarud_cart_recovery_settings', 'isarud_email_marketing_settings', 'isarud_email_log', 'isarud_upsell_settings', 'isarud_upsell_rules', 'isarud_api_key', 'isarud_auto_screen', 'isarud_block_match', 'isarud_alert_email', 'isarud_webhook_secret', 'isarud_auto_import_orders', 'isarud_category_mappings'];
    289128        $settings = [];
    290129        foreach ($option_keys as $key) {
    291130            $value = get_option($key, null);
    292             if ($value !== null) {
    293                 $settings[] = [
    294                     'key' => $key,
    295                     'value' => is_array($value) ? $value : json_decode($value, true),
    296                 ];
     131            if ($value !== null && $value !== false) {
     132                $settings[] = ['key' => $key, 'value' => is_array($value) ? $value : (is_string($value) ? (json_decode($value, true) ?? $value) : $value)];
    297133            }
    298134        }
    299 
    300         if (empty($settings)) {
    301             return ['success' => true, 'synced' => 0, 'message' => 'No settings to sync'];
    302         }
    303 
    304         $result = $this->api_request('settings/sync', ['settings' => $settings]);
    305 
    306         return $result;
     135        if (empty($settings)) return ['success' => true, 'synced' => 0, 'message' => 'No settings to sync'];
     136        return $this->api_request('settings/sync', ['settings' => $settings]);
    307137    }
    308138
    309139    private function sync_customers(): array {
    310         if (!class_exists('WooCommerce')) {
    311             return ['success' => true, 'synced' => 0, 'message' => 'WooCommerce not active'];
    312         }
    313 
     140        if (!class_exists('WooCommerce')) return ['success' => true, 'synced' => 0];
    314141        $segment_settings = get_option('isarud_segment_settings', []);
    315142        $b2b_settings = get_option('isarud_b2b_settings', []);
    316 
    317         $customers_query = new \WC_Customer_Query([
    318             'limit' => 500,
    319             'orderby' => 'date_created',
    320             'order' => 'DESC',
    321         ]);
    322 
    323         $wc_customers = $customers_query->get_customers();
    324 
    325         if (empty($wc_customers)) {
    326             return ['success' => true, 'synced' => 0, 'message' => 'No customers'];
    327         }
    328 
     143        $wc_customers = (new \WC_Customer_Query(['limit' => 500, 'orderby' => 'date_created', 'order' => 'DESC']))->get_customers();
     144        if (empty($wc_customers)) return ['success' => true, 'synced' => 0];
    329145        $customers_data = [];
    330146        foreach ($wc_customers as $customer) {
    331             $customer_id = $customer->get_id();
    332             $order_count = (int)$customer->get_order_count();
    333             $total_spent = (float)$customer->get_total_spent();
    334 
    335             $segment = $this->determine_segment($customer_id, $order_count, $total_spent, $segment_settings);
    336 
    337             $b2b_discount = 0;
    338             $company = $customer->get_billing_company();
    339             if (!empty($b2b_settings['enabled']) && $b2b_settings['enabled'] === 'yes') {
    340                 $b2b_discount = (float)get_user_meta($customer_id, '_isarud_b2b_discount', true);
    341             }
    342 
    343             $customers_data[] = [
    344                 'external_id' => $customer_id,
    345                 'email' => $customer->get_email(),
    346                 'name' => trim($customer->get_first_name() . ' ' . $customer->get_last_name()),
    347                 'company' => $company ?: null,
    348                 'segment' => $segment,
    349                 'discount_rate' => $b2b_discount,
    350                 'total_orders' => $order_count,
    351                 'total_spent' => $total_spent,
    352                 'meta' => [
    353                     'billing_country' => $customer->get_billing_country(),
    354                     'billing_city' => $customer->get_billing_city(),
    355                     'phone' => $customer->get_billing_phone(),
    356                     'date_created' => $customer->get_date_created() ? $customer->get_date_created()->format('Y-m-d H:i:s') : null,
    357                 ],
    358             ];
    359         }
    360 
    361         $total_synced = 0;
    362         $total_failed = 0;
    363 
    364         foreach (array_chunk($customers_data, 100) as $chunk) {
    365             $result = $this->api_request('customers/sync', ['customers' => $chunk]);
    366             if (isset($result['error'])) {
    367                 $total_failed += count($chunk);
    368             } else {
    369                 $total_synced += $result['synced'] ?? 0;
    370                 $total_failed += $result['failed'] ?? 0;
    371             }
    372         }
    373 
    374         return ['success' => true, 'synced' => $total_synced, 'failed' => $total_failed];
    375     }
    376 
    377     private function determine_segment(int $customer_id, int $order_count, float $total_spent, array $settings): string {
    378         $vip_threshold = (float)($settings['vip_min_spent'] ?? 5000);
    379         $loyal_threshold = (int)($settings['loyal_min_orders'] ?? 5);
    380         $risk_days = (int)($settings['risk_inactive_days'] ?? 180);
    381 
    382         if ($total_spent >= $vip_threshold) return 'vip';
    383         if ($order_count >= $loyal_threshold) return 'loyal';
    384         if ($order_count === 1) return 'one_time';
    385         if ($order_count === 0) return 'new';
    386 
    387         $last_order_date = get_user_meta($customer_id, '_last_order_date', true);
    388         if ($last_order_date) {
    389             $days_since = (int)((time() - strtotime($last_order_date)) / 86400);
    390             if ($days_since > $risk_days) return 'churned';
    391             if ($days_since > ($risk_days / 2)) return 'at_risk';
    392         }
    393 
     147            $cid = $customer->get_id(); $oc = (int)$customer->get_order_count(); $ts = (float)$customer->get_total_spent();
     148            $b2b_discount = (!empty($b2b_settings['enabled']) && $b2b_settings['enabled'] === 'yes') ? (float)get_user_meta($cid, '_isarud_b2b_discount', true) : 0;
     149            $customers_data[] = ['external_id' => $cid, 'email' => $customer->get_email(), 'name' => trim($customer->get_first_name() . ' ' . $customer->get_last_name()), 'company' => $customer->get_billing_company() ?: null, 'segment' => $this->determine_segment($cid, $oc, $ts, $segment_settings), 'discount_rate' => $b2b_discount, 'total_orders' => $oc, 'total_spent' => $ts, 'meta' => ['billing_country' => $customer->get_billing_country(), 'billing_city' => $customer->get_billing_city(), 'phone' => $customer->get_billing_phone(), 'date_created' => $customer->get_date_created() ? $customer->get_date_created()->format('Y-m-d H:i:s') : null]];
     150        }
     151        $ts2 = 0; $tf2 = 0;
     152        foreach (array_chunk($customers_data, 100) as $chunk) { $r = $this->api_request('customers/sync', ['customers' => $chunk]); if (isset($r['error'])) $tf2 += count($chunk); else { $ts2 += $r['synced'] ?? 0; $tf2 += $r['failed'] ?? 0; } }
     153        return ['success' => true, 'synced' => $ts2, 'failed' => $tf2];
     154    }
     155
     156    private function determine_segment(int $cid, int $oc, float $ts, array $s): string {
     157        $vip = (float)($s['vip_min_spent'] ?? 5000); $loyal = (int)($s['loyal_min_orders'] ?? 5); $risk = (int)($s['risk_inactive_days'] ?? 180);
     158        if ($ts >= $vip) return 'vip'; if ($oc >= $loyal) return 'loyal'; if ($oc === 1) return 'one_time'; if ($oc === 0) return 'new';
     159        $ld = get_user_meta($cid, '_last_order_date', true);
     160        if ($ld) { $ds = (int)((time() - strtotime($ld)) / 86400); if ($ds > $risk) return 'churned'; if ($ds > ($risk / 2)) return 'at_risk'; }
    394161        return 'regular';
    395162    }
    396163
    397164    private function sync_abandoned_carts(): array {
    398         global $wpdb;
    399         $table = $wpdb->prefix . 'isarud_abandoned_carts';
    400 
    401         if ($wpdb->get_var("SHOW TABLES LIKE '{$table}'") !== $table) {
    402             return ['success' => true, 'synced' => 0, 'message' => 'Abandoned carts table not found'];
    403         }
    404 
    405         $carts = $wpdb->get_results("SELECT * FROM {$table} ORDER BY updated_at DESC LIMIT 500");
    406 
    407         if (empty($carts)) {
    408             return ['success' => true, 'synced' => 0, 'message' => 'No abandoned carts'];
    409         }
    410 
    411         $carts_data = [];
    412         foreach ($carts as $cart) {
    413             $cart_items = maybe_unserialize($cart->cart_contents ?? '');
    414             if (is_string($cart_items)) {
    415                 $cart_items = json_decode($cart_items, true);
    416             }
    417 
    418             $carts_data[] = [
    419                 'external_id' => (int)$cart->id,
    420                 'session_id' => $cart->session_id ?? null,
    421                 'email' => $cart->email ?? null,
    422                 'customer_name' => $cart->customer_name ?? null,
    423                 'cart_total' => (float)($cart->cart_total ?? 0),
    424                 'cart_items' => is_array($cart_items) ? $cart_items : null,
    425                 'status' => $cart->status ?? 'abandoned',
    426                 'emails_sent' => (int)($cart->emails_sent ?? 0),
    427                 'last_email_at' => $cart->last_email_at ?? null,
    428                 'recovered_at' => $cart->recovered_at ?? null,
    429                 'cart_date' => $cart->created_at ?? $cart->updated_at ?? null,
    430             ];
    431         }
    432 
    433         $total_synced = 0;
    434         $total_failed = 0;
    435 
    436         foreach (array_chunk($carts_data, 100) as $chunk) {
    437             $result = $this->api_request('abandoned-carts/sync', ['carts' => $chunk]);
    438             if (isset($result['error'])) {
    439                 $total_failed += count($chunk);
    440             } else {
    441                 $total_synced += $result['synced'] ?? 0;
    442                 $total_failed += $result['failed'] ?? 0;
    443             }
    444         }
    445 
    446         return ['success' => true, 'synced' => $total_synced, 'failed' => $total_failed];
     165        global $wpdb; $t = $wpdb->prefix . 'isarud_abandoned_carts';
     166        if ($wpdb->get_var("SHOW TABLES LIKE '{$t}'") !== $t) return ['success' => true, 'synced' => 0, 'message' => 'Table not found'];
     167        $rows = $wpdb->get_results("SELECT * FROM {$t} ORDER BY updated_at DESC LIMIT 500");
     168        if (empty($rows)) return ['success' => true, 'synced' => 0];
     169        $data = [];
     170        foreach ($rows as $r) { $ci = maybe_unserialize($r->cart_contents ?? ''); if (is_string($ci)) $ci = json_decode($ci, true); $data[] = ['external_id' => (int)$r->id, 'session_id' => $r->session_id ?? null, 'email' => $r->email ?? null, 'customer_name' => $r->customer_name ?? null, 'cart_total' => (float)($r->cart_total ?? 0), 'cart_items' => is_array($ci) ? $ci : null, 'status' => $r->status ?? 'abandoned', 'emails_sent' => (int)($r->emails_sent ?? 0), 'last_email_at' => $r->last_email_at ?? null, 'recovered_at' => $r->recovered_at ?? null, 'cart_date' => $r->created_at ?? $r->updated_at ?? null]; }
     171        $ts = 0; $tf = 0;
     172        foreach (array_chunk($data, 100) as $chunk) { $res = $this->api_request('abandoned-carts/sync', ['carts' => $chunk]); if (isset($res['error'])) $tf += count($chunk); else { $ts += $res['synced'] ?? 0; $tf += $res['failed'] ?? 0; } }
     173        return ['success' => true, 'synced' => $ts, 'failed' => $tf];
    447174    }
    448175
    449176    private function sync_einvoices(): array {
    450         global $wpdb;
    451         $table = $wpdb->prefix . 'isarud_einvoices';
    452 
    453         if ($wpdb->get_var("SHOW TABLES LIKE '{$table}'") !== $table) {
    454             return ['success' => true, 'synced' => 0, 'message' => 'Einvoices table not found'];
    455         }
    456 
    457         $invoices = $wpdb->get_results("SELECT * FROM {$table} ORDER BY created_at DESC LIMIT 500");
    458 
    459         if (empty($invoices)) {
    460             return ['success' => true, 'synced' => 0, 'message' => 'No einvoices'];
    461         }
    462 
    463         $invoices_data = [];
    464         foreach ($invoices as $inv) {
    465             $gib_response = $inv->gib_response ?? null;
    466             if (is_string($gib_response)) {
    467                 $gib_response = json_decode($gib_response, true);
    468             }
    469 
    470             $invoices_data[] = [
    471                 'external_id' => (int)$inv->id,
    472                 'order_id' => (int)($inv->order_id ?? 0),
    473                 'invoice_number' => $inv->invoice_number ?? null,
    474                 'invoice_type' => $inv->invoice_type ?? 'einvoice',
    475                 'customer_name' => $inv->customer_name ?? null,
    476                 'customer_tax_id' => $inv->tax_id ?? $inv->customer_tax_id ?? null,
    477                 'total' => (float)($inv->total ?? 0),
    478                 'currency' => $inv->currency ?? 'TRY',
    479                 'status' => $inv->status ?? 'draft',
    480                 'gib_response' => is_array($gib_response) ? $gib_response : null,
    481                 'invoice_date' => $inv->invoice_date ?? $inv->created_at ?? null,
    482             ];
    483         }
    484 
    485         $total_synced = 0;
    486         $total_failed = 0;
    487 
    488         foreach (array_chunk($invoices_data, 100) as $chunk) {
    489             $result = $this->api_request('einvoices/sync', ['einvoices' => $chunk]);
    490             if (isset($result['error'])) {
    491                 $total_failed += count($chunk);
    492             } else {
    493                 $total_synced += $result['synced'] ?? 0;
    494                 $total_failed += $result['failed'] ?? 0;
    495             }
    496         }
    497 
    498         return ['success' => true, 'synced' => $total_synced, 'failed' => $total_failed];
    499     }
    500 
    501     /**
    502      * Run full cloud sync (products + orders + extended) — called by cron
    503      */
     177        global $wpdb; $t = $wpdb->prefix . 'isarud_einvoices';
     178        if ($wpdb->get_var("SHOW TABLES LIKE '{$t}'") !== $t) return ['success' => true, 'synced' => 0, 'message' => 'Table not found'];
     179        $rows = $wpdb->get_results("SELECT * FROM {$t} ORDER BY created_at DESC LIMIT 500");
     180        if (empty($rows)) return ['success' => true, 'synced' => 0];
     181        $data = [];
     182        foreach ($rows as $r) { $gr = $r->gib_response ?? null; if (is_string($gr)) $gr = json_decode($gr, true); $data[] = ['external_id' => (int)$r->id, 'order_id' => (int)($r->order_id ?? 0), 'invoice_number' => $r->invoice_number ?? null, 'invoice_type' => $r->invoice_type ?? 'einvoice', 'customer_name' => $r->customer_name ?? null, 'customer_tax_id' => $r->tax_id ?? $r->customer_tax_id ?? null, 'total' => (float)($r->total ?? 0), 'currency' => $r->currency ?? 'TRY', 'status' => $r->status ?? 'draft', 'gib_response' => is_array($gr) ? $gr : null, 'invoice_date' => $r->invoice_date ?? $r->created_at ?? null]; }
     183        $ts = 0; $tf = 0;
     184        foreach (array_chunk($data, 100) as $chunk) { $res = $this->api_request('einvoices/sync', ['einvoices' => $chunk]); if (isset($res['error'])) $tf += count($chunk); else { $ts += $res['synced'] ?? 0; $tf += $res['failed'] ?? 0; } }
     185        return ['success' => true, 'synced' => $ts, 'failed' => $tf];
     186    }
     187
     188    private function sync_credentials(): array {
     189        global $wpdb; $rows = $wpdb->get_results("SELECT * FROM {$wpdb->prefix}isarud_credentials ORDER BY id ASC");
     190        if (empty($rows)) return ['success' => true, 'synced' => 0];
     191        $data = [];
     192        foreach ($rows as $r) $data[] = ['marketplace' => $r->marketplace, 'is_active' => (bool)$r->is_active, 'price_margin' => (float)$r->price_margin, 'price_margin_type' => $r->price_margin_type ?? 'percent', 'auto_sync' => (bool)$r->auto_sync, 'sync_interval' => $r->sync_interval ?? 'daily', 'last_test' => $r->last_test, 'test_status' => $r->test_status, 'last_sync' => $r->last_sync];
     193        return $this->api_request('credentials/sync', ['credentials' => $data]);
     194    }
     195
     196    private function sync_screening_logs(): array {
     197        global $wpdb; $t = $wpdb->prefix . 'isarud_screening_log';
     198        if ($wpdb->get_var("SHOW TABLES LIKE '{$t}'") !== $t) return ['success' => true, 'synced' => 0];
     199        $rows = $wpdb->get_results("SELECT * FROM {$t} ORDER BY created_at DESC LIMIT 500");
     200        if (empty($rows)) return ['success' => true, 'synced' => 0];
     201        $data = [];
     202        foreach ($rows as $r) { $ns = is_string($r->names_screened) ? json_decode($r->names_screened, true) : $r->names_screened; $rs = is_string($r->results) ? json_decode($r->results, true) : $r->results; $data[] = ['external_id' => (int)$r->id, 'order_id' => (int)($r->order_id ?? 0), 'names_screened' => is_array($ns) ? $ns : null, 'has_match' => (bool)($r->has_match ?? false), 'results' => is_array($rs) ? $rs : null, 'created_at' => $r->created_at]; }
     203        $ts = 0; $tf = 0;
     204        foreach (array_chunk($data, 100) as $chunk) { $res = $this->api_request('screening-logs/sync', ['logs' => $chunk]); if (isset($res['error'])) $tf += count($chunk); else { $ts += $res['synced'] ?? 0; $tf += $res['failed'] ?? 0; } }
     205        return ['success' => true, 'synced' => $ts, 'failed' => $tf];
     206    }
     207
     208    private function sync_sync_logs(): array {
     209        global $wpdb; $t = $wpdb->prefix . 'isarud_sync_log';
     210        if ($wpdb->get_var("SHOW TABLES LIKE '{$t}'") !== $t) return ['success' => true, 'synced' => 0];
     211        $rows = $wpdb->get_results("SELECT * FROM {$t} ORDER BY created_at DESC LIMIT 500");
     212        if (empty($rows)) return ['success' => true, 'synced' => 0];
     213        $data = [];
     214        foreach ($rows as $r) $data[] = ['external_id' => (int)$r->id, 'product_id' => (int)($r->product_id ?? 0), 'marketplace' => $r->marketplace ?? null, 'action' => $r->action ?? null, 'status' => $r->status ?? null, 'message' => $r->message ?? null, 'created_at' => $r->created_at];
     215        $ts = 0; $tf = 0;
     216        foreach (array_chunk($data, 100) as $chunk) { $res = $this->api_request('sync-logs/sync', ['logs' => $chunk]); if (isset($res['error'])) $tf += count($chunk); else { $ts += $res['synced'] ?? 0; $tf += $res['failed'] ?? 0; } }
     217        return ['success' => true, 'synced' => $ts, 'failed' => $tf];
     218    }
     219
     220    private function sync_suppliers(): array {
     221        global $wpdb; $t = $wpdb->prefix . 'isarud_dropship_suppliers';
     222        if ($wpdb->get_var("SHOW TABLES LIKE '{$t}'") !== $t) return ['success' => true, 'synced' => 0];
     223        $rows = $wpdb->get_results("SELECT * FROM {$t} ORDER BY id ASC");
     224        if (empty($rows)) return ['success' => true, 'synced' => 0];
     225        $data = [];
     226        foreach ($rows as $r) $data[] = ['external_id' => (int)$r->id, 'name' => $r->name, 'email' => $r->email ?? null, 'api_url' => $r->api_url ?? null, 'auto_forward' => (bool)($r->auto_forward ?? false), 'commission_rate' => (float)($r->commission_rate ?? 0), 'is_active' => (bool)($r->is_active ?? true)];
     227        return $this->api_request('suppliers/sync', ['suppliers' => $data]);
     228    }
     229
     230    private function sync_affiliates(): array {
     231        global $wpdb; $t = $wpdb->prefix . 'isarud_affiliates';
     232        if ($wpdb->get_var("SHOW TABLES LIKE '{$t}'") !== $t) return ['success' => true, 'synced' => 0];
     233        $rows = $wpdb->get_results("SELECT * FROM {$t} ORDER BY id ASC");
     234        if (empty($rows)) return ['success' => true, 'synced' => 0];
     235        $data = [];
     236        foreach ($rows as $r) $data[] = ['external_id' => (int)$r->id, 'name' => $r->name, 'email' => $r->email ?? null, 'code' => $r->code ?? null, 'commission_rate' => (float)($r->commission_rate ?? 10), 'total_sales' => (float)($r->total_sales ?? 0), 'total_commission' => (float)($r->total_commission ?? 0), 'is_active' => (bool)($r->is_active ?? true)];
     237        return $this->api_request('affiliates/sync', ['affiliates' => $data]);
     238    }
     239
    504240    public function run_cloud_sync(): void {
    505241        if (!$this->is_enabled()) return;
    506 
    507         $this->sync_products();
    508         $this->sync_orders();
    509         $this->sync_extended_data();
    510 
     242        $this->sync_products(); $this->sync_orders(); $this->sync_extended_data();
    511243        update_option('isarud_cloud_last_sync', current_time('mysql'));
    512244    }
    513245
    514     /**
    515      * Manual trigger for extended sync only
    516      */
    517246    public function run_extended_sync_now(): array {
    518         if (!$this->is_enabled()) {
    519             return ['error' => 'Cloud sync not enabled'];
    520         }
    521 
     247        if (!$this->is_enabled()) return ['error' => 'Cloud sync not enabled'];
    522248        return $this->sync_extended_data();
    523249    }
    524250
    525251    private function apply_margin(float $price, string $mp): float {
    526         $plugin = Isarud_Plugin::instance();
    527         if (method_exists($plugin, 'sync_stock_public')) {
    528             global $wpdb;
    529             $row = $wpdb->get_row($wpdb->prepare(
    530                 "SELECT price_margin, price_margin_type FROM {$wpdb->prefix}isarud_credentials WHERE marketplace=%s",
    531                 $mp
    532             ));
    533             if ($row && floatval($row->price_margin) != 0) {
    534                 return $row->price_margin_type === 'percent'
    535                     ? round($price * (1 + floatval($row->price_margin) / 100), 2)
    536                     : round($price + floatval($row->price_margin), 2);
    537             }
    538         }
     252        global $wpdb;
     253        $row = $wpdb->get_row($wpdb->prepare("SELECT price_margin, price_margin_type FROM {$wpdb->prefix}isarud_credentials WHERE marketplace=%s", $mp));
     254        if ($row && floatval($row->price_margin) != 0) return $row->price_margin_type === 'percent' ? round($price * (1 + floatval($row->price_margin) / 100), 2) : round($price + floatval($row->price_margin), 2);
    539255        return $price;
    540256    }
    541257
    542258    public function get_status(): array {
    543         return [
    544             'enabled' => $this->is_enabled(),
    545             'cloud_key' => !empty($this->get_cloud_key()) ? '••••' . substr($this->get_cloud_key(), -8) : '',
    546             'last_sync' => get_option('isarud_cloud_last_sync', ''),
    547             'last_product_sync' => get_option('isarud_cloud_last_product_sync', ''),
    548             'last_order_sync' => get_option('isarud_cloud_last_order_sync', ''),
    549             'last_extended_sync' => get_option('isarud_cloud_last_extended_sync', ''),
    550         ];
     259        return ['enabled' => $this->is_enabled(), 'cloud_key' => !empty($this->get_cloud_key()) ? '••••' . substr($this->get_cloud_key(), -8) : '', 'last_sync' => get_option('isarud_cloud_last_sync', ''), 'last_product_sync' => get_option('isarud_cloud_last_product_sync', ''), 'last_order_sync' => get_option('isarud_cloud_last_order_sync', ''), 'last_extended_sync' => get_option('isarud_cloud_last_extended_sync', '')];
    551260    }
    552261
    553262    public function disconnect(): void {
    554         delete_option('isarud_cloud_api_key');
    555         delete_option('isarud_cloud_enabled');
    556         delete_option('isarud_cloud_platform_id');
    557         delete_option('isarud_cloud_last_sync');
    558         delete_option('isarud_cloud_last_product_sync');
    559         delete_option('isarud_cloud_last_order_sync');
    560         delete_option('isarud_cloud_last_extended_sync');
     263        delete_option('isarud_cloud_api_key'); delete_option('isarud_cloud_enabled'); delete_option('isarud_cloud_platform_id');
     264        delete_option('isarud_cloud_last_sync'); delete_option('isarud_cloud_last_product_sync'); delete_option('isarud_cloud_last_order_sync'); delete_option('isarud_cloud_last_extended_sync');
    561265        wp_clear_scheduled_hook('isarud_cloud_sync_hook');
    562266    }
  • api-isarud/tags/6.2.0/readme-tr_TR.txt

    r3493435 r3493482  
    55Tested up to: 6.9
    66Requires PHP: 8.0
    7 Stable tag: 6.1.0
     7Stable tag: 6.2.0
    88License: GPLv2 or later
    99
  • api-isarud/tags/6.2.0/readme.txt

    r3493435 r3493482  
    55Tested up to: 6.9
    66Requires PHP: 8.0
    7 Stable tag: 6.1.0
     7Stable tag: 6.2.0
    88License: GPLv2 or later
    99
  • api-isarud/trunk/api-isarud.php

    r3493435 r3493482  
    1717if (!defined('ABSPATH')) exit;
    1818
    19 define('ISARUD_VERSION', '6.1.0');
     19define('ISARUD_VERSION', '6.2.0');
    2020define('ISARUD_DIR', plugin_dir_path(__FILE__));
    2121define('ISARUD_URL', plugin_dir_url(__FILE__));
  • api-isarud/trunk/isarud-cloud-sync.php

    r3493435 r3493482  
    22/**
    33 * Isarud Cloud Sync — isarud.com API v2 entegrasyonu
    4  * WP Plugin v6.1.0
     4 * WP Plugin v6.2.0
    55 */
    66if (!defined('ABSPATH')) exit;
     
    1919        add_action('isarud_cloud_sync_hook', [$this, 'run_cloud_sync']);
    2020        add_action('woocommerce_new_order', [$this, 'sync_order_to_cloud'], 40, 1);
    21 
    2221        if (get_option('isarud_cloud_enabled') === 'yes') {
    2322            if (!wp_next_scheduled('isarud_cloud_sync_hook')) {
     
    2726    }
    2827
    29     private function get_cloud_key(): string {
    30         return get_option('isarud_cloud_api_key', '');
    31     }
    32 
    33     public function is_enabled(): bool {
    34         return get_option('isarud_cloud_enabled') === 'yes' && !empty($this->get_cloud_key());
    35     }
     28    private function get_cloud_key(): string { return get_option('isarud_cloud_api_key', ''); }
     29    public function is_enabled(): bool { return get_option('isarud_cloud_enabled') === 'yes' && !empty($this->get_cloud_key()); }
    3630
    3731    private function api_request(string $endpoint, array $data = [], string $method = 'POST'): array {
    3832        $key = $this->get_cloud_key();
    3933        if (empty($key)) return ['error' => 'Cloud API key not configured'];
    40 
    41         $args = [
    42             'method' => $method,
    43             'timeout' => 30,
    44             'headers' => [
    45                 'Content-Type' => 'application/json',
    46                 'X-Marketplace-Key' => $key,
    47                 'User-Agent' => 'IsarudWP/' . ISARUD_VERSION,
    48             ],
    49         ];
    50 
    51         if (!empty($data) && in_array($method, ['POST', 'PUT'])) {
    52             $args['body'] = wp_json_encode($data);
    53         }
    54 
     34        $args = ['method' => $method, 'timeout' => 30, 'headers' => ['Content-Type' => 'application/json', 'X-Marketplace-Key' => $key, 'User-Agent' => 'IsarudWP/' . ISARUD_VERSION]];
     35        if (!empty($data) && in_array($method, ['POST', 'PUT'])) $args['body'] = wp_json_encode($data);
    5536        $response = wp_remote_request($this->api_base . $endpoint, $args);
    56 
    57         if (is_wp_error($response)) {
    58             return ['error' => $response->get_error_message()];
    59         }
    60 
     37        if (is_wp_error($response)) return ['error' => $response->get_error_message()];
    6138        $code = wp_remote_retrieve_response_code($response);
    6239        $body = json_decode(wp_remote_retrieve_body($response), true) ?: [];
    63 
    64         if ($code >= 400) {
    65             return ['error' => $body['error'] ?? "HTTP {$code}"];
    66         }
    67 
     40        if ($code >= 400) return ['error' => $body['error'] ?? "HTTP {$code}"];
    6841        return $body;
    6942    }
    7043
    7144    public function connect_site(string $bearer_token): array {
    72         $response = wp_remote_post('https://isarud.com/api/v2/marketplace/connect', [
    73             'timeout' => 30,
    74             'headers' => [
    75                 'Content-Type' => 'application/json',
    76                 'Authorization' => 'Bearer ' . $bearer_token,
    77             ],
    78             'body' => wp_json_encode([
    79                 'platform' => 'wordpress',
    80                 'site_url' => home_url(),
    81                 'site_name' => get_bloginfo('name'),
    82             ]),
    83         ]);
    84 
    85         if (is_wp_error($response)) {
    86             return ['error' => $response->get_error_message()];
    87         }
    88 
     45        $response = wp_remote_post('https://isarud.com/api/v2/marketplace/connect', ['timeout' => 30, 'headers' => ['Content-Type' => 'application/json', 'Authorization' => 'Bearer ' . $bearer_token], 'body' => wp_json_encode(['platform' => 'wordpress', 'site_url' => home_url(), 'site_name' => get_bloginfo('name')])]);
     46        if (is_wp_error($response)) return ['error' => $response->get_error_message()];
    8947        $body = json_decode(wp_remote_retrieve_body($response), true) ?: [];
    90 
    9148        if (!empty($body['success']) && !empty($body['platform']['api_key'])) {
    9249            update_option('isarud_cloud_api_key', $body['platform']['api_key']);
     
    9653            return ['success' => true, 'message' => 'Connected to isarud.com'];
    9754        }
    98 
    99         if (isset($body['error']) && strpos($body['error'], 'already connected') !== false) {
    100             return ['success' => true, 'message' => 'Already connected'];
    101         }
    102 
     55        if (isset($body['error']) && strpos($body['error'], 'already connected') !== false) return ['success' => true, 'message' => 'Already connected'];
    10356        return ['error' => $body['error'] ?? 'Connection failed'];
    10457    }
    10558
    10659    public function sync_products(): array {
    107         if (!$this->is_enabled() || !class_exists('WooCommerce')) {
    108             return ['error' => 'Cloud sync not enabled or WooCommerce not active'];
    109         }
    110 
     60        if (!$this->is_enabled() || !class_exists('WooCommerce')) return ['error' => 'Cloud sync not enabled or WooCommerce not active'];
    11161        global $wpdb;
    112         $marketplaces = $wpdb->get_results(
    113             "SELECT marketplace FROM {$wpdb->prefix}isarud_credentials WHERE is_active=1"
    114         );
    115 
     62        $marketplaces = $wpdb->get_results("SELECT marketplace FROM {$wpdb->prefix}isarud_credentials WHERE is_active=1");
    11663        $products_data = [];
    11764        $wc_products = wc_get_products(['status' => 'publish', 'limit' => 500]);
    118 
    11965        foreach ($wc_products as $product) {
    120             $products_data[] = [
    121                 'external_id' => (string)$product->get_id(),
    122                 'marketplace' => 'woocommerce',
    123                 'title' => $product->get_name(),
    124                 'sku' => $product->get_sku(),
    125                 'price' => (float)$product->get_price(),
    126                 'stock' => $product->get_stock_quantity() ?? 0,
    127                 'status' => $product->get_status(),
    128                 'image_url' => wp_get_attachment_url($product->get_image_id()) ?: null,
    129                 'meta' => [
    130                     'barcode' => get_post_meta($product->get_id(), '_isarud_barcode', true),
    131                     'permalink' => $product->get_permalink(),
    132                 ],
    133             ];
    134 
     66            $products_data[] = ['external_id' => (string)$product->get_id(), 'marketplace' => 'woocommerce', 'title' => $product->get_name(), 'sku' => $product->get_sku(), 'price' => (float)$product->get_price(), 'stock' => $product->get_stock_quantity() ?? 0, 'status' => $product->get_status(), 'image_url' => wp_get_attachment_url($product->get_image_id()) ?: null, 'meta' => ['barcode' => get_post_meta($product->get_id(), '_isarud_barcode', true), 'permalink' => $product->get_permalink()]];
    13567            foreach ($marketplaces as $mp) {
    13668                $barcode = get_post_meta($product->get_id(), '_isarud_barcode', true) ?: $product->get_sku();
    13769                if (empty($barcode)) continue;
    138 
    139                 $products_data[] = [
    140                     'external_id' => $barcode,
    141                     'marketplace' => $mp->marketplace,
    142                     'title' => $product->get_name(),
    143                     'sku' => $product->get_sku(),
    144                     'price' => $this->apply_margin((float)$product->get_price(), $mp->marketplace),
    145                     'stock' => $product->get_stock_quantity() ?? 0,
    146                     'status' => $product->get_status(),
    147                     'image_url' => wp_get_attachment_url($product->get_image_id()) ?: null,
    148                 ];
     70                $products_data[] = ['external_id' => $barcode, 'marketplace' => $mp->marketplace, 'title' => $product->get_name(), 'sku' => $product->get_sku(), 'price' => $this->apply_margin((float)$product->get_price(), $mp->marketplace), 'stock' => $product->get_stock_quantity() ?? 0, 'status' => $product->get_status(), 'image_url' => wp_get_attachment_url($product->get_image_id()) ?: null];
    14971            }
    15072        }
    151 
    152         if (empty($products_data)) {
    153             return ['success' => true, 'synced' => 0, 'message' => 'No products to sync'];
    154         }
    155 
    156         $total_synced = 0;
    157         $total_failed = 0;
    158 
     73        if (empty($products_data)) return ['success' => true, 'synced' => 0, 'message' => 'No products to sync'];
     74        $total_synced = 0; $total_failed = 0;
    15975        foreach (array_chunk($products_data, 100) as $chunk) {
    16076            $result = $this->api_request('products/sync', ['products' => $chunk]);
    161             if (isset($result['error'])) {
    162                 $total_failed += count($chunk);
    163             } else {
    164                 $total_synced += $result['synced'] ?? 0;
    165                 $total_failed += $result['failed'] ?? 0;
    166             }
    167         }
    168 
     77            if (isset($result['error'])) $total_failed += count($chunk); else { $total_synced += $result['synced'] ?? 0; $total_failed += $result['failed'] ?? 0; }
     78        }
    16979        update_option('isarud_cloud_last_product_sync', current_time('mysql'));
    170 
    171         return [
    172             'success' => true,
    173             'synced' => $total_synced,
    174             'failed' => $total_failed,
    175         ];
     80        return ['success' => true, 'synced' => $total_synced, 'failed' => $total_failed];
    17681    }
    17782
    17883    public function sync_orders(): array {
    179         if (!$this->is_enabled() || !class_exists('WooCommerce')) {
    180             return ['error' => 'Cloud sync not enabled'];
    181         }
    182 
     84        if (!$this->is_enabled() || !class_exists('WooCommerce')) return ['error' => 'Cloud sync not enabled'];
    18385        $last_sync = get_option('isarud_cloud_last_order_sync', '2000-01-01 00:00:00');
    184 
    185         $orders = wc_get_orders([
    186             'date_created' => '>' . strtotime($last_sync),
    187             'limit' => 500,
    188             'orderby' => 'date',
    189             'order' => 'ASC',
    190         ]);
    191 
    192         if (empty($orders)) {
    193             return ['success' => true, 'synced' => 0, 'message' => 'No new orders'];
    194         }
    195 
     86        $orders = wc_get_orders(['date_created' => '>' . strtotime($last_sync), 'limit' => 500, 'orderby' => 'date', 'order' => 'ASC']);
     87        if (empty($orders)) return ['success' => true, 'synced' => 0, 'message' => 'No new orders'];
    19688        $orders_data = [];
    197         foreach ($orders as $order) {
    198             $orders_data[] = $this->format_order($order);
    199         }
    200 
    201         $total_synced = 0;
    202         $total_failed = 0;
    203 
     89        foreach ($orders as $order) $orders_data[] = $this->format_order($order);
     90        $total_synced = 0; $total_failed = 0;
    20491        foreach (array_chunk($orders_data, 100) as $chunk) {
    20592            $result = $this->api_request('orders/sync', ['orders' => $chunk]);
    206             if (isset($result['error'])) {
    207                 $total_failed += count($chunk);
    208             } else {
    209                 $total_synced += $result['synced'] ?? 0;
    210                 $total_failed += $result['failed'] ?? 0;
    211             }
    212         }
    213 
     93            if (isset($result['error'])) $total_failed += count($chunk); else { $total_synced += $result['synced'] ?? 0; $total_failed += $result['failed'] ?? 0; }
     94        }
    21495        update_option('isarud_cloud_last_order_sync', current_time('mysql'));
    215 
    216         return [
    217             'success' => true,
    218             'synced' => $total_synced,
    219             'failed' => $total_failed,
    220         ];
     96        return ['success' => true, 'synced' => $total_synced, 'failed' => $total_failed];
    22197    }
    22298
    22399    public function sync_order_to_cloud(int $order_id): void {
    224100        if (!$this->is_enabled()) return;
    225 
    226101        $order = wc_get_order($order_id);
    227102        if (!$order) return;
    228 
    229         $this->api_request('orders/sync', [
    230             'orders' => [$this->format_order($order)],
    231         ]);
     103        $this->api_request('orders/sync', ['orders' => [$this->format_order($order)]]);
    232104    }
    233105
    234106    private function format_order($order): array {
    235         return [
    236             'external_id' => (string)$order->get_id(),
    237             'marketplace' => 'woocommerce',
    238             'customer_name' => trim($order->get_billing_first_name() . ' ' . $order->get_billing_last_name()),
    239             'customer_email' => $order->get_billing_email(),
    240             'total' => (float)$order->get_total(),
    241             'currency' => $order->get_currency(),
    242             'status' => $order->get_status(),
    243             'order_date' => $order->get_date_created()?->format('Y-m-d H:i:s'),
    244             'meta' => [
    245                 'billing_country' => $order->get_billing_country(),
    246                 'shipping_country' => $order->get_shipping_country(),
    247                 'payment_method' => $order->get_payment_method(),
    248                 'items_count' => $order->get_item_count(),
    249             ],
    250         ];
    251     }
    252 
    253     /**
    254      * Sync extended data: settings, customers, abandoned carts, einvoices
    255      */
     107        return ['external_id' => (string)$order->get_id(), 'marketplace' => 'woocommerce', 'customer_name' => trim($order->get_billing_first_name() . ' ' . $order->get_billing_last_name()), 'customer_email' => $order->get_billing_email(), 'total' => (float)$order->get_total(), 'currency' => $order->get_currency(), 'status' => $order->get_status(), 'order_date' => $order->get_date_created()?->format('Y-m-d H:i:s'), 'meta' => ['billing_country' => $order->get_billing_country(), 'shipping_country' => $order->get_shipping_country(), 'payment_method' => $order->get_payment_method(), 'items_count' => $order->get_item_count()]];
     108    }
     109
    256110    public function sync_extended_data(): array {
    257         if (!$this->is_enabled()) {
    258             return ['error' => 'Cloud sync not enabled'];
    259         }
    260 
     111        if (!$this->is_enabled()) return ['error' => 'Cloud sync not enabled'];
    261112        $results = [];
    262 
    263113        $results['settings'] = $this->sync_settings();
    264114        $results['customers'] = $this->sync_customers();
    265115        $results['abandoned_carts'] = $this->sync_abandoned_carts();
    266116        $results['einvoices'] = $this->sync_einvoices();
    267 
     117        $results['credentials'] = $this->sync_credentials();
     118        $results['screening_logs'] = $this->sync_screening_logs();
     119        $results['sync_logs'] = $this->sync_sync_logs();
     120        $results['suppliers'] = $this->sync_suppliers();
     121        $results['affiliates'] = $this->sync_affiliates();
    268122        update_option('isarud_cloud_last_extended_sync', current_time('mysql'));
    269 
    270123        return $results;
    271124    }
    272125
    273126    private function sync_settings(): array {
    274         $option_keys = [
    275             'isarud_b2b_settings',
    276             'isarud_currency_settings',
    277             'isarud_tcmb_rates',
    278             'isarud_segment_settings',
    279             'isarud_einvoice_settings',
    280             'isarud_popup_settings',
    281             'isarud_popup_campaigns',
    282             'isarud_cart_recovery_settings',
    283             'isarud_email_marketing_settings',
    284             'isarud_email_log',
    285             'isarud_upsell_settings',
    286             'isarud_upsell_rules',
    287         ];
    288 
     127        $option_keys = ['isarud_b2b_settings', 'isarud_currency_settings', 'isarud_tcmb_rates', 'isarud_segment_settings', 'isarud_einvoice_settings', 'isarud_popup_settings', 'isarud_popup_campaigns', 'isarud_cart_recovery_settings', 'isarud_email_marketing_settings', 'isarud_email_log', 'isarud_upsell_settings', 'isarud_upsell_rules', 'isarud_api_key', 'isarud_auto_screen', 'isarud_block_match', 'isarud_alert_email', 'isarud_webhook_secret', 'isarud_auto_import_orders', 'isarud_category_mappings'];
    289128        $settings = [];
    290129        foreach ($option_keys as $key) {
    291130            $value = get_option($key, null);
    292             if ($value !== null) {
    293                 $settings[] = [
    294                     'key' => $key,
    295                     'value' => is_array($value) ? $value : json_decode($value, true),
    296                 ];
     131            if ($value !== null && $value !== false) {
     132                $settings[] = ['key' => $key, 'value' => is_array($value) ? $value : (is_string($value) ? (json_decode($value, true) ?? $value) : $value)];
    297133            }
    298134        }
    299 
    300         if (empty($settings)) {
    301             return ['success' => true, 'synced' => 0, 'message' => 'No settings to sync'];
    302         }
    303 
    304         $result = $this->api_request('settings/sync', ['settings' => $settings]);
    305 
    306         return $result;
     135        if (empty($settings)) return ['success' => true, 'synced' => 0, 'message' => 'No settings to sync'];
     136        return $this->api_request('settings/sync', ['settings' => $settings]);
    307137    }
    308138
    309139    private function sync_customers(): array {
    310         if (!class_exists('WooCommerce')) {
    311             return ['success' => true, 'synced' => 0, 'message' => 'WooCommerce not active'];
    312         }
    313 
     140        if (!class_exists('WooCommerce')) return ['success' => true, 'synced' => 0];
    314141        $segment_settings = get_option('isarud_segment_settings', []);
    315142        $b2b_settings = get_option('isarud_b2b_settings', []);
    316 
    317         $customers_query = new \WC_Customer_Query([
    318             'limit' => 500,
    319             'orderby' => 'date_created',
    320             'order' => 'DESC',
    321         ]);
    322 
    323         $wc_customers = $customers_query->get_customers();
    324 
    325         if (empty($wc_customers)) {
    326             return ['success' => true, 'synced' => 0, 'message' => 'No customers'];
    327         }
    328 
     143        $wc_customers = (new \WC_Customer_Query(['limit' => 500, 'orderby' => 'date_created', 'order' => 'DESC']))->get_customers();
     144        if (empty($wc_customers)) return ['success' => true, 'synced' => 0];
    329145        $customers_data = [];
    330146        foreach ($wc_customers as $customer) {
    331             $customer_id = $customer->get_id();
    332             $order_count = (int)$customer->get_order_count();
    333             $total_spent = (float)$customer->get_total_spent();
    334 
    335             $segment = $this->determine_segment($customer_id, $order_count, $total_spent, $segment_settings);
    336 
    337             $b2b_discount = 0;
    338             $company = $customer->get_billing_company();
    339             if (!empty($b2b_settings['enabled']) && $b2b_settings['enabled'] === 'yes') {
    340                 $b2b_discount = (float)get_user_meta($customer_id, '_isarud_b2b_discount', true);
    341             }
    342 
    343             $customers_data[] = [
    344                 'external_id' => $customer_id,
    345                 'email' => $customer->get_email(),
    346                 'name' => trim($customer->get_first_name() . ' ' . $customer->get_last_name()),
    347                 'company' => $company ?: null,
    348                 'segment' => $segment,
    349                 'discount_rate' => $b2b_discount,
    350                 'total_orders' => $order_count,
    351                 'total_spent' => $total_spent,
    352                 'meta' => [
    353                     'billing_country' => $customer->get_billing_country(),
    354                     'billing_city' => $customer->get_billing_city(),
    355                     'phone' => $customer->get_billing_phone(),
    356                     'date_created' => $customer->get_date_created() ? $customer->get_date_created()->format('Y-m-d H:i:s') : null,
    357                 ],
    358             ];
    359         }
    360 
    361         $total_synced = 0;
    362         $total_failed = 0;
    363 
    364         foreach (array_chunk($customers_data, 100) as $chunk) {
    365             $result = $this->api_request('customers/sync', ['customers' => $chunk]);
    366             if (isset($result['error'])) {
    367                 $total_failed += count($chunk);
    368             } else {
    369                 $total_synced += $result['synced'] ?? 0;
    370                 $total_failed += $result['failed'] ?? 0;
    371             }
    372         }
    373 
    374         return ['success' => true, 'synced' => $total_synced, 'failed' => $total_failed];
    375     }
    376 
    377     private function determine_segment(int $customer_id, int $order_count, float $total_spent, array $settings): string {
    378         $vip_threshold = (float)($settings['vip_min_spent'] ?? 5000);
    379         $loyal_threshold = (int)($settings['loyal_min_orders'] ?? 5);
    380         $risk_days = (int)($settings['risk_inactive_days'] ?? 180);
    381 
    382         if ($total_spent >= $vip_threshold) return 'vip';
    383         if ($order_count >= $loyal_threshold) return 'loyal';
    384         if ($order_count === 1) return 'one_time';
    385         if ($order_count === 0) return 'new';
    386 
    387         $last_order_date = get_user_meta($customer_id, '_last_order_date', true);
    388         if ($last_order_date) {
    389             $days_since = (int)((time() - strtotime($last_order_date)) / 86400);
    390             if ($days_since > $risk_days) return 'churned';
    391             if ($days_since > ($risk_days / 2)) return 'at_risk';
    392         }
    393 
     147            $cid = $customer->get_id(); $oc = (int)$customer->get_order_count(); $ts = (float)$customer->get_total_spent();
     148            $b2b_discount = (!empty($b2b_settings['enabled']) && $b2b_settings['enabled'] === 'yes') ? (float)get_user_meta($cid, '_isarud_b2b_discount', true) : 0;
     149            $customers_data[] = ['external_id' => $cid, 'email' => $customer->get_email(), 'name' => trim($customer->get_first_name() . ' ' . $customer->get_last_name()), 'company' => $customer->get_billing_company() ?: null, 'segment' => $this->determine_segment($cid, $oc, $ts, $segment_settings), 'discount_rate' => $b2b_discount, 'total_orders' => $oc, 'total_spent' => $ts, 'meta' => ['billing_country' => $customer->get_billing_country(), 'billing_city' => $customer->get_billing_city(), 'phone' => $customer->get_billing_phone(), 'date_created' => $customer->get_date_created() ? $customer->get_date_created()->format('Y-m-d H:i:s') : null]];
     150        }
     151        $ts2 = 0; $tf2 = 0;
     152        foreach (array_chunk($customers_data, 100) as $chunk) { $r = $this->api_request('customers/sync', ['customers' => $chunk]); if (isset($r['error'])) $tf2 += count($chunk); else { $ts2 += $r['synced'] ?? 0; $tf2 += $r['failed'] ?? 0; } }
     153        return ['success' => true, 'synced' => $ts2, 'failed' => $tf2];
     154    }
     155
     156    private function determine_segment(int $cid, int $oc, float $ts, array $s): string {
     157        $vip = (float)($s['vip_min_spent'] ?? 5000); $loyal = (int)($s['loyal_min_orders'] ?? 5); $risk = (int)($s['risk_inactive_days'] ?? 180);
     158        if ($ts >= $vip) return 'vip'; if ($oc >= $loyal) return 'loyal'; if ($oc === 1) return 'one_time'; if ($oc === 0) return 'new';
     159        $ld = get_user_meta($cid, '_last_order_date', true);
     160        if ($ld) { $ds = (int)((time() - strtotime($ld)) / 86400); if ($ds > $risk) return 'churned'; if ($ds > ($risk / 2)) return 'at_risk'; }
    394161        return 'regular';
    395162    }
    396163
    397164    private function sync_abandoned_carts(): array {
    398         global $wpdb;
    399         $table = $wpdb->prefix . 'isarud_abandoned_carts';
    400 
    401         if ($wpdb->get_var("SHOW TABLES LIKE '{$table}'") !== $table) {
    402             return ['success' => true, 'synced' => 0, 'message' => 'Abandoned carts table not found'];
    403         }
    404 
    405         $carts = $wpdb->get_results("SELECT * FROM {$table} ORDER BY updated_at DESC LIMIT 500");
    406 
    407         if (empty($carts)) {
    408             return ['success' => true, 'synced' => 0, 'message' => 'No abandoned carts'];
    409         }
    410 
    411         $carts_data = [];
    412         foreach ($carts as $cart) {
    413             $cart_items = maybe_unserialize($cart->cart_contents ?? '');
    414             if (is_string($cart_items)) {
    415                 $cart_items = json_decode($cart_items, true);
    416             }
    417 
    418             $carts_data[] = [
    419                 'external_id' => (int)$cart->id,
    420                 'session_id' => $cart->session_id ?? null,
    421                 'email' => $cart->email ?? null,
    422                 'customer_name' => $cart->customer_name ?? null,
    423                 'cart_total' => (float)($cart->cart_total ?? 0),
    424                 'cart_items' => is_array($cart_items) ? $cart_items : null,
    425                 'status' => $cart->status ?? 'abandoned',
    426                 'emails_sent' => (int)($cart->emails_sent ?? 0),
    427                 'last_email_at' => $cart->last_email_at ?? null,
    428                 'recovered_at' => $cart->recovered_at ?? null,
    429                 'cart_date' => $cart->created_at ?? $cart->updated_at ?? null,
    430             ];
    431         }
    432 
    433         $total_synced = 0;
    434         $total_failed = 0;
    435 
    436         foreach (array_chunk($carts_data, 100) as $chunk) {
    437             $result = $this->api_request('abandoned-carts/sync', ['carts' => $chunk]);
    438             if (isset($result['error'])) {
    439                 $total_failed += count($chunk);
    440             } else {
    441                 $total_synced += $result['synced'] ?? 0;
    442                 $total_failed += $result['failed'] ?? 0;
    443             }
    444         }
    445 
    446         return ['success' => true, 'synced' => $total_synced, 'failed' => $total_failed];
     165        global $wpdb; $t = $wpdb->prefix . 'isarud_abandoned_carts';
     166        if ($wpdb->get_var("SHOW TABLES LIKE '{$t}'") !== $t) return ['success' => true, 'synced' => 0, 'message' => 'Table not found'];
     167        $rows = $wpdb->get_results("SELECT * FROM {$t} ORDER BY updated_at DESC LIMIT 500");
     168        if (empty($rows)) return ['success' => true, 'synced' => 0];
     169        $data = [];
     170        foreach ($rows as $r) { $ci = maybe_unserialize($r->cart_contents ?? ''); if (is_string($ci)) $ci = json_decode($ci, true); $data[] = ['external_id' => (int)$r->id, 'session_id' => $r->session_id ?? null, 'email' => $r->email ?? null, 'customer_name' => $r->customer_name ?? null, 'cart_total' => (float)($r->cart_total ?? 0), 'cart_items' => is_array($ci) ? $ci : null, 'status' => $r->status ?? 'abandoned', 'emails_sent' => (int)($r->emails_sent ?? 0), 'last_email_at' => $r->last_email_at ?? null, 'recovered_at' => $r->recovered_at ?? null, 'cart_date' => $r->created_at ?? $r->updated_at ?? null]; }
     171        $ts = 0; $tf = 0;
     172        foreach (array_chunk($data, 100) as $chunk) { $res = $this->api_request('abandoned-carts/sync', ['carts' => $chunk]); if (isset($res['error'])) $tf += count($chunk); else { $ts += $res['synced'] ?? 0; $tf += $res['failed'] ?? 0; } }
     173        return ['success' => true, 'synced' => $ts, 'failed' => $tf];
    447174    }
    448175
    449176    private function sync_einvoices(): array {
    450         global $wpdb;
    451         $table = $wpdb->prefix . 'isarud_einvoices';
    452 
    453         if ($wpdb->get_var("SHOW TABLES LIKE '{$table}'") !== $table) {
    454             return ['success' => true, 'synced' => 0, 'message' => 'Einvoices table not found'];
    455         }
    456 
    457         $invoices = $wpdb->get_results("SELECT * FROM {$table} ORDER BY created_at DESC LIMIT 500");
    458 
    459         if (empty($invoices)) {
    460             return ['success' => true, 'synced' => 0, 'message' => 'No einvoices'];
    461         }
    462 
    463         $invoices_data = [];
    464         foreach ($invoices as $inv) {
    465             $gib_response = $inv->gib_response ?? null;
    466             if (is_string($gib_response)) {
    467                 $gib_response = json_decode($gib_response, true);
    468             }
    469 
    470             $invoices_data[] = [
    471                 'external_id' => (int)$inv->id,
    472                 'order_id' => (int)($inv->order_id ?? 0),
    473                 'invoice_number' => $inv->invoice_number ?? null,
    474                 'invoice_type' => $inv->invoice_type ?? 'einvoice',
    475                 'customer_name' => $inv->customer_name ?? null,
    476                 'customer_tax_id' => $inv->tax_id ?? $inv->customer_tax_id ?? null,
    477                 'total' => (float)($inv->total ?? 0),
    478                 'currency' => $inv->currency ?? 'TRY',
    479                 'status' => $inv->status ?? 'draft',
    480                 'gib_response' => is_array($gib_response) ? $gib_response : null,
    481                 'invoice_date' => $inv->invoice_date ?? $inv->created_at ?? null,
    482             ];
    483         }
    484 
    485         $total_synced = 0;
    486         $total_failed = 0;
    487 
    488         foreach (array_chunk($invoices_data, 100) as $chunk) {
    489             $result = $this->api_request('einvoices/sync', ['einvoices' => $chunk]);
    490             if (isset($result['error'])) {
    491                 $total_failed += count($chunk);
    492             } else {
    493                 $total_synced += $result['synced'] ?? 0;
    494                 $total_failed += $result['failed'] ?? 0;
    495             }
    496         }
    497 
    498         return ['success' => true, 'synced' => $total_synced, 'failed' => $total_failed];
    499     }
    500 
    501     /**
    502      * Run full cloud sync (products + orders + extended) — called by cron
    503      */
     177        global $wpdb; $t = $wpdb->prefix . 'isarud_einvoices';
     178        if ($wpdb->get_var("SHOW TABLES LIKE '{$t}'") !== $t) return ['success' => true, 'synced' => 0, 'message' => 'Table not found'];
     179        $rows = $wpdb->get_results("SELECT * FROM {$t} ORDER BY created_at DESC LIMIT 500");
     180        if (empty($rows)) return ['success' => true, 'synced' => 0];
     181        $data = [];
     182        foreach ($rows as $r) { $gr = $r->gib_response ?? null; if (is_string($gr)) $gr = json_decode($gr, true); $data[] = ['external_id' => (int)$r->id, 'order_id' => (int)($r->order_id ?? 0), 'invoice_number' => $r->invoice_number ?? null, 'invoice_type' => $r->invoice_type ?? 'einvoice', 'customer_name' => $r->customer_name ?? null, 'customer_tax_id' => $r->tax_id ?? $r->customer_tax_id ?? null, 'total' => (float)($r->total ?? 0), 'currency' => $r->currency ?? 'TRY', 'status' => $r->status ?? 'draft', 'gib_response' => is_array($gr) ? $gr : null, 'invoice_date' => $r->invoice_date ?? $r->created_at ?? null]; }
     183        $ts = 0; $tf = 0;
     184        foreach (array_chunk($data, 100) as $chunk) { $res = $this->api_request('einvoices/sync', ['einvoices' => $chunk]); if (isset($res['error'])) $tf += count($chunk); else { $ts += $res['synced'] ?? 0; $tf += $res['failed'] ?? 0; } }
     185        return ['success' => true, 'synced' => $ts, 'failed' => $tf];
     186    }
     187
     188    private function sync_credentials(): array {
     189        global $wpdb; $rows = $wpdb->get_results("SELECT * FROM {$wpdb->prefix}isarud_credentials ORDER BY id ASC");
     190        if (empty($rows)) return ['success' => true, 'synced' => 0];
     191        $data = [];
     192        foreach ($rows as $r) $data[] = ['marketplace' => $r->marketplace, 'is_active' => (bool)$r->is_active, 'price_margin' => (float)$r->price_margin, 'price_margin_type' => $r->price_margin_type ?? 'percent', 'auto_sync' => (bool)$r->auto_sync, 'sync_interval' => $r->sync_interval ?? 'daily', 'last_test' => $r->last_test, 'test_status' => $r->test_status, 'last_sync' => $r->last_sync];
     193        return $this->api_request('credentials/sync', ['credentials' => $data]);
     194    }
     195
     196    private function sync_screening_logs(): array {
     197        global $wpdb; $t = $wpdb->prefix . 'isarud_screening_log';
     198        if ($wpdb->get_var("SHOW TABLES LIKE '{$t}'") !== $t) return ['success' => true, 'synced' => 0];
     199        $rows = $wpdb->get_results("SELECT * FROM {$t} ORDER BY created_at DESC LIMIT 500");
     200        if (empty($rows)) return ['success' => true, 'synced' => 0];
     201        $data = [];
     202        foreach ($rows as $r) { $ns = is_string($r->names_screened) ? json_decode($r->names_screened, true) : $r->names_screened; $rs = is_string($r->results) ? json_decode($r->results, true) : $r->results; $data[] = ['external_id' => (int)$r->id, 'order_id' => (int)($r->order_id ?? 0), 'names_screened' => is_array($ns) ? $ns : null, 'has_match' => (bool)($r->has_match ?? false), 'results' => is_array($rs) ? $rs : null, 'created_at' => $r->created_at]; }
     203        $ts = 0; $tf = 0;
     204        foreach (array_chunk($data, 100) as $chunk) { $res = $this->api_request('screening-logs/sync', ['logs' => $chunk]); if (isset($res['error'])) $tf += count($chunk); else { $ts += $res['synced'] ?? 0; $tf += $res['failed'] ?? 0; } }
     205        return ['success' => true, 'synced' => $ts, 'failed' => $tf];
     206    }
     207
     208    private function sync_sync_logs(): array {
     209        global $wpdb; $t = $wpdb->prefix . 'isarud_sync_log';
     210        if ($wpdb->get_var("SHOW TABLES LIKE '{$t}'") !== $t) return ['success' => true, 'synced' => 0];
     211        $rows = $wpdb->get_results("SELECT * FROM {$t} ORDER BY created_at DESC LIMIT 500");
     212        if (empty($rows)) return ['success' => true, 'synced' => 0];
     213        $data = [];
     214        foreach ($rows as $r) $data[] = ['external_id' => (int)$r->id, 'product_id' => (int)($r->product_id ?? 0), 'marketplace' => $r->marketplace ?? null, 'action' => $r->action ?? null, 'status' => $r->status ?? null, 'message' => $r->message ?? null, 'created_at' => $r->created_at];
     215        $ts = 0; $tf = 0;
     216        foreach (array_chunk($data, 100) as $chunk) { $res = $this->api_request('sync-logs/sync', ['logs' => $chunk]); if (isset($res['error'])) $tf += count($chunk); else { $ts += $res['synced'] ?? 0; $tf += $res['failed'] ?? 0; } }
     217        return ['success' => true, 'synced' => $ts, 'failed' => $tf];
     218    }
     219
     220    private function sync_suppliers(): array {
     221        global $wpdb; $t = $wpdb->prefix . 'isarud_dropship_suppliers';
     222        if ($wpdb->get_var("SHOW TABLES LIKE '{$t}'") !== $t) return ['success' => true, 'synced' => 0];
     223        $rows = $wpdb->get_results("SELECT * FROM {$t} ORDER BY id ASC");
     224        if (empty($rows)) return ['success' => true, 'synced' => 0];
     225        $data = [];
     226        foreach ($rows as $r) $data[] = ['external_id' => (int)$r->id, 'name' => $r->name, 'email' => $r->email ?? null, 'api_url' => $r->api_url ?? null, 'auto_forward' => (bool)($r->auto_forward ?? false), 'commission_rate' => (float)($r->commission_rate ?? 0), 'is_active' => (bool)($r->is_active ?? true)];
     227        return $this->api_request('suppliers/sync', ['suppliers' => $data]);
     228    }
     229
     230    private function sync_affiliates(): array {
     231        global $wpdb; $t = $wpdb->prefix . 'isarud_affiliates';
     232        if ($wpdb->get_var("SHOW TABLES LIKE '{$t}'") !== $t) return ['success' => true, 'synced' => 0];
     233        $rows = $wpdb->get_results("SELECT * FROM {$t} ORDER BY id ASC");
     234        if (empty($rows)) return ['success' => true, 'synced' => 0];
     235        $data = [];
     236        foreach ($rows as $r) $data[] = ['external_id' => (int)$r->id, 'name' => $r->name, 'email' => $r->email ?? null, 'code' => $r->code ?? null, 'commission_rate' => (float)($r->commission_rate ?? 10), 'total_sales' => (float)($r->total_sales ?? 0), 'total_commission' => (float)($r->total_commission ?? 0), 'is_active' => (bool)($r->is_active ?? true)];
     237        return $this->api_request('affiliates/sync', ['affiliates' => $data]);
     238    }
     239
    504240    public function run_cloud_sync(): void {
    505241        if (!$this->is_enabled()) return;
    506 
    507         $this->sync_products();
    508         $this->sync_orders();
    509         $this->sync_extended_data();
    510 
     242        $this->sync_products(); $this->sync_orders(); $this->sync_extended_data();
    511243        update_option('isarud_cloud_last_sync', current_time('mysql'));
    512244    }
    513245
    514     /**
    515      * Manual trigger for extended sync only
    516      */
    517246    public function run_extended_sync_now(): array {
    518         if (!$this->is_enabled()) {
    519             return ['error' => 'Cloud sync not enabled'];
    520         }
    521 
     247        if (!$this->is_enabled()) return ['error' => 'Cloud sync not enabled'];
    522248        return $this->sync_extended_data();
    523249    }
    524250
    525251    private function apply_margin(float $price, string $mp): float {
    526         $plugin = Isarud_Plugin::instance();
    527         if (method_exists($plugin, 'sync_stock_public')) {
    528             global $wpdb;
    529             $row = $wpdb->get_row($wpdb->prepare(
    530                 "SELECT price_margin, price_margin_type FROM {$wpdb->prefix}isarud_credentials WHERE marketplace=%s",
    531                 $mp
    532             ));
    533             if ($row && floatval($row->price_margin) != 0) {
    534                 return $row->price_margin_type === 'percent'
    535                     ? round($price * (1 + floatval($row->price_margin) / 100), 2)
    536                     : round($price + floatval($row->price_margin), 2);
    537             }
    538         }
     252        global $wpdb;
     253        $row = $wpdb->get_row($wpdb->prepare("SELECT price_margin, price_margin_type FROM {$wpdb->prefix}isarud_credentials WHERE marketplace=%s", $mp));
     254        if ($row && floatval($row->price_margin) != 0) return $row->price_margin_type === 'percent' ? round($price * (1 + floatval($row->price_margin) / 100), 2) : round($price + floatval($row->price_margin), 2);
    539255        return $price;
    540256    }
    541257
    542258    public function get_status(): array {
    543         return [
    544             'enabled' => $this->is_enabled(),
    545             'cloud_key' => !empty($this->get_cloud_key()) ? '••••' . substr($this->get_cloud_key(), -8) : '',
    546             'last_sync' => get_option('isarud_cloud_last_sync', ''),
    547             'last_product_sync' => get_option('isarud_cloud_last_product_sync', ''),
    548             'last_order_sync' => get_option('isarud_cloud_last_order_sync', ''),
    549             'last_extended_sync' => get_option('isarud_cloud_last_extended_sync', ''),
    550         ];
     259        return ['enabled' => $this->is_enabled(), 'cloud_key' => !empty($this->get_cloud_key()) ? '••••' . substr($this->get_cloud_key(), -8) : '', 'last_sync' => get_option('isarud_cloud_last_sync', ''), 'last_product_sync' => get_option('isarud_cloud_last_product_sync', ''), 'last_order_sync' => get_option('isarud_cloud_last_order_sync', ''), 'last_extended_sync' => get_option('isarud_cloud_last_extended_sync', '')];
    551260    }
    552261
    553262    public function disconnect(): void {
    554         delete_option('isarud_cloud_api_key');
    555         delete_option('isarud_cloud_enabled');
    556         delete_option('isarud_cloud_platform_id');
    557         delete_option('isarud_cloud_last_sync');
    558         delete_option('isarud_cloud_last_product_sync');
    559         delete_option('isarud_cloud_last_order_sync');
    560         delete_option('isarud_cloud_last_extended_sync');
     263        delete_option('isarud_cloud_api_key'); delete_option('isarud_cloud_enabled'); delete_option('isarud_cloud_platform_id');
     264        delete_option('isarud_cloud_last_sync'); delete_option('isarud_cloud_last_product_sync'); delete_option('isarud_cloud_last_order_sync'); delete_option('isarud_cloud_last_extended_sync');
    561265        wp_clear_scheduled_hook('isarud_cloud_sync_hook');
    562266    }
  • api-isarud/trunk/readme-tr_TR.txt

    r3493435 r3493482  
    55Tested up to: 6.9
    66Requires PHP: 8.0
    7 Stable tag: 6.1.0
     7Stable tag: 6.2.0
    88License: GPLv2 or later
    99
  • api-isarud/trunk/readme.txt

    r3493435 r3493482  
    55Tested up to: 6.9
    66Requires PHP: 8.0
    7 Stable tag: 6.1.0
     7Stable tag: 6.2.0
    88License: GPLv2 or later
    99
Note: See TracChangeset for help on using the changeset viewer.