Plugin Directory

Changeset 3493435


Ignore:
Timestamp:
03/28/2026 03:39:15 PM (5 days ago)
Author:
durasi
Message:

v6.1.0: sync trunk with Extended Cloud Sync

Location:
api-isarud/trunk
Files:
2 added
10 deleted
4 edited

Legend:

Unmodified
Added
Removed
  • api-isarud/trunk/api-isarud.php

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

    r3490819 r3493435  
    22/**
    33 * Isarud Cloud Sync — isarud.com API v2 entegrasyonu
    4  * WP Plugin v3.0
     4 * WP Plugin v6.1.0
    55 */
    66if (!defined('ABSPATH')) exit;
     
    1717
    1818    public function __construct() {
    19         // Cloud sync on cron
    2019        add_action('isarud_cloud_sync_hook', [$this, 'run_cloud_sync']);
    21 
    22         // Sync on new order (after screening)
    2320        add_action('woocommerce_new_order', [$this, 'sync_order_to_cloud'], 40, 1);
    2421
    25         // Schedule cloud sync cron if enabled
    2622        if (get_option('isarud_cloud_enabled') === 'yes') {
    2723            if (!wp_next_scheduled('isarud_cloud_sync_hook')) {
     
    3127    }
    3228
    33     /**
    34      * Get the marketplace API key for cloud sync
    35      */
    3629    private function get_cloud_key(): string {
    3730        return get_option('isarud_cloud_api_key', '');
    3831    }
    3932
    40     /**
    41      * Check if cloud sync is enabled and configured
    42      */
    4333    public function is_enabled(): bool {
    4434        return get_option('isarud_cloud_enabled') === 'yes' && !empty($this->get_cloud_key());
    4535    }
    4636
    47     /**
    48      * API request to isarud.com
    49      */
    5037    private function api_request(string $endpoint, array $data = [], string $method = 'POST'): array {
    5138        $key = $this->get_cloud_key();
     
    8269    }
    8370
    84     /**
    85      * Connect this WP site to isarud.com
    86      * Called when user saves cloud settings with Bearer token auth
    87      */
    8871    public function connect_site(string $bearer_token): array {
    8972        $response = wp_remote_post('https://isarud.com/api/v2/marketplace/connect', [
     
    10891        if (!empty($body['success']) && !empty($body['platform']['api_key'])) {
    10992            update_option('isarud_cloud_api_key', $body['platform']['api_key']);
    110             update_option('isarud_api_key', $bearer_token); // Screening için user API key
     93            update_option('isarud_api_key', $bearer_token);
    11194            update_option('isarud_cloud_enabled', 'yes');
    11295            update_option('isarud_cloud_platform_id', $body['platform']['id']);
     
    11497        }
    11598
    116         // Already connected — might have api_key from before
    11799        if (isset($body['error']) && strpos($body['error'], 'already connected') !== false) {
    118100            return ['success' => true, 'message' => 'Already connected'];
     
    122104    }
    123105
    124     /**
    125      * Sync all WooCommerce products to isarud.com
    126      */
    127106    public function sync_products(): array {
    128107        if (!$this->is_enabled() || !class_exists('WooCommerce')) {
     
    139118
    140119        foreach ($wc_products as $product) {
    141             // Base product entry (WooCommerce)
    142120            $products_data[] = [
    143121                'external_id' => (string)$product->get_id(),
     
    155133            ];
    156134
    157             // Per-marketplace entries
    158135            foreach ($marketplaces as $mp) {
    159136                $barcode = get_post_meta($product->get_id(), '_isarud_barcode', true) ?: $product->get_sku();
     
    177154        }
    178155
    179         // Send in chunks of 100
    180156        $total_synced = 0;
    181157        $total_failed = 0;
     
    200176    }
    201177
    202     /**
    203      * Sync recent orders to isarud.com
    204      */
    205178    public function sync_orders(): array {
    206179        if (!$this->is_enabled() || !class_exists('WooCommerce')) {
     
    226199        }
    227200
    228         // Send in chunks of 100
    229201        $total_synced = 0;
    230202        $total_failed = 0;
     
    249221    }
    250222
    251     /**
    252      * Sync single order to cloud (called on woocommerce_new_order)
    253      */
    254223    public function sync_order_to_cloud(int $order_id): void {
    255224        if (!$this->is_enabled()) return;
     
    263232    }
    264233
    265     /**
    266      * Format WC order for API
    267      */
    268234    private function format_order($order): array {
    269235        return [
     
    286252
    287253    /**
    288      * Run full cloud sync (products + orders) — called by cron
     254     * Sync extended data: settings, customers, abandoned carts, einvoices
     255     */
     256    public function sync_extended_data(): array {
     257        if (!$this->is_enabled()) {
     258            return ['error' => 'Cloud sync not enabled'];
     259        }
     260
     261        $results = [];
     262
     263        $results['settings'] = $this->sync_settings();
     264        $results['customers'] = $this->sync_customers();
     265        $results['abandoned_carts'] = $this->sync_abandoned_carts();
     266        $results['einvoices'] = $this->sync_einvoices();
     267
     268        update_option('isarud_cloud_last_extended_sync', current_time('mysql'));
     269
     270        return $results;
     271    }
     272
     273    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
     289        $settings = [];
     290        foreach ($option_keys as $key) {
     291            $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                ];
     297            }
     298        }
     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;
     307    }
     308
     309    private function sync_customers(): array {
     310        if (!class_exists('WooCommerce')) {
     311            return ['success' => true, 'synced' => 0, 'message' => 'WooCommerce not active'];
     312        }
     313
     314        $segment_settings = get_option('isarud_segment_settings', []);
     315        $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
     329        $customers_data = [];
     330        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
     394        return 'regular';
     395    }
     396
     397    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];
     447    }
     448
     449    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
    289503     */
    290504    public function run_cloud_sync(): void {
     
    293507        $this->sync_products();
    294508        $this->sync_orders();
     509        $this->sync_extended_data();
    295510
    296511        update_option('isarud_cloud_last_sync', current_time('mysql'));
     
    298513
    299514    /**
    300      * Get margin for marketplace (delegates to main plugin)
     515     * Manual trigger for extended sync only
    301516     */
     517    public function run_extended_sync_now(): array {
     518        if (!$this->is_enabled()) {
     519            return ['error' => 'Cloud sync not enabled'];
     520        }
     521
     522        return $this->sync_extended_data();
     523    }
     524
    302525    private function apply_margin(float $price, string $mp): float {
    303526        $plugin = Isarud_Plugin::instance();
    304527        if (method_exists($plugin, 'sync_stock_public')) {
    305             // Use reflection or direct DB query
    306528            global $wpdb;
    307529            $row = $wpdb->get_row($wpdb->prepare(
     
    318540    }
    319541
    320     /**
    321      * Get sync status for display
    322      */
    323542    public function get_status(): array {
    324543        return [
     
    328547            'last_product_sync' => get_option('isarud_cloud_last_product_sync', ''),
    329548            'last_order_sync' => get_option('isarud_cloud_last_order_sync', ''),
     549            'last_extended_sync' => get_option('isarud_cloud_last_extended_sync', ''),
    330550        ];
    331551    }
    332552
    333     /**
    334      * Disconnect from isarud.com
    335      */
    336553    public function disconnect(): void {
    337554        delete_option('isarud_cloud_api_key');
     
    341558        delete_option('isarud_cloud_last_product_sync');
    342559        delete_option('isarud_cloud_last_order_sync');
     560        delete_option('isarud_cloud_last_extended_sync');
    343561        wp_clear_scheduled_hook('isarud_cloud_sync_hook');
    344562    }
  • api-isarud/trunk/readme-tr_TR.txt

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

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