Plugin Directory

Changeset 3439817


Ignore:
Timestamp:
01/14/2026 07:57:51 PM (3 months ago)
Author:
meliconnect
Message:

Update trunk to version 1.4.0

Location:
meliconnect/trunk
Files:
15 edited

Legend:

Unmodified
Added
Removed
  • meliconnect/trunk/assets/css/plugin-pages.css

    r3408382 r3439817  
    271271
    272272
    273 .meliconnect-select:not(.is-multiple):not(.is-loading)::after {
     273.meliconnect-select:not(.is-multiple):not(.meliconnect-is-loading)::after {
    274274    border: none !important;
    275275}
  • meliconnect/trunk/includes/Core/Assets/Js/meliconnect-setting.js

    r3367389 r3439817  
    158158                processData: false,
    159159                beforeSend: function () {
    160                     $('#save-import-button').addClass('is-loading');
     160                    $('#save-import-button').addClass('meliconnect-is-loading');
    161161                },
    162162                success: function (response) {
     
    164164                },
    165165                error: function (xhr, status, error) {
    166                     $('#save-import-button').removeClass('is-loading');
     166                    $('#save-import-button').removeClass('meliconnect-is-loading');
    167167                    console.log(xhr.responseText);
    168168                }
     
    198198            processData: false,
    199199            beforeSend: function () {
    200                 jQuery('#save-export-button').addClass('is-loading');
     200                jQuery('#save-export-button').addClass('meliconnect-is-loading');
    201201            },
    202202            success: function (response) {
     
    204204            },
    205205            error: function (xhr, status, error) {
    206                 jQuery('#save-export-button').removeClass('is-loading');
     206                jQuery('#save-export-button').removeClass('meliconnect-is-loading');
    207207                console.log(xhr.responseText);
    208208            }
     
    269269                processData: false,
    270270                beforeSend: function () {
    271                     $('#save-import-button').addClass('is-loading');
     271                    $('#save-import-button').addClass('meliconnect-is-loading');
    272272                },
    273273                success: function (response) {
     
    329329                processData: false,
    330330                beforeSend: function () {
    331                     $('#save-sync-button').addClass('is-loading');
     331                    $('#save-sync-button').addClass('meliconnect-is-loading');
    332332                },
    333333                success: function (response) {
     
    335335                },
    336336                error: function (xhr, status, error) {
    337                     $('#save-sync-button').removeClass('is-loading');
     337                    $('#save-sync-button').removeClass('meliconnect-is-loading');
    338338                    console.log(xhr.responseText);
    339339                }
  • meliconnect/trunk/includes/Core/CronManager.php

    r3408382 r3439817  
    231231
    232232    public function processUserCustomImport() {
    233         global $wpdb;
    234         $meli_listing_ids_arr = array();
    235 
    236         $lock = get_option( $this->custom_import_lock_option_name );
    237 
    238         if ( $lock ) {
    239             Helper::logData( 'Custom import is in process. Aborting.', 'custom-import' );
    240             return;
    241         }
    242 
    243         // Update lock
    244         update_option( $this->custom_import_lock_option_name, time() );
    245 
    246         try {
    247             // 1- Get pending items from process items table
    248             $items_to_process = $this->get_pending_items_to_process( 'custom-import' );
    249 
    250             if ( empty( $items_to_process ) ) {
    251                 return;
    252             }
    253 
    254             Helper::logData( 'Items to process: ' . count( $items_to_process ), 'custom-import' );
    255 
    256             // Create instances of the dependencies needed for ProductDataFacade
    257             $wooCommerceAdapter     = new WooCommerceProductAdapter();
    258             $productCreationService = new WooCommerceProductCreationService();
    259             $productDataFacade      = new ProductDataFacade( $wooCommerceAdapter, $productCreationService );
    260 
    261             foreach ( $items_to_process as $item ) {
    262                 // Verificar si se ha solicitado la cancelación
    263                 $cancel_requested = get_option( 'meliconnect_import_cancel_requested' );
    264 
    265                 Helper::logData( 'Cancel requested: ' . $cancel_requested, 'custom-import' );
    266                 if ( $cancel_requested ) {
    267 
    268                     Helper::logData( 'Custom import canceled by user. Exiting process.', 'custom-import' );
    269 
    270                     UserListingToImport::update_processing_listings( 'canceled' );
    271 
    272                     throw new \Exception( 'Custom import canceled by user.' );
    273                 }
    274 
    275                 Helper::logData( 'Processing listing id: ' . $item->meli_listing_id . ' - Status: ' . $item->process_status, 'custom-import' );
    276 
    277                 try {
    278                     // Iniciar la transacción para el ítem actual
    279                     $wpdb->query( 'START TRANSACTION' );
    280 
    281                     // 2- Format items data to send, Send data to API server and Get response and process response creating or updating items in WooCommerce
    282                     $productDataFacade->importAndCreateProduct( $item->meli_listing_id, $item->meli_user_id, $item->template_id, $item->woo_product_id );
    283 
    284                     // 3- Update process and process items table
    285                     $process = ProcessItems::updateProcessedItemStatus( $item->id, 'processed', $item->process_id );
    286 
    287                     Helper::logData( 'Process: ' . wp_json_encode( $process ), 'custom-import' );
    288 
    289                     $meli_listing_ids_arr = array_merge( $meli_listing_ids_arr, array( $item->meli_listing_id ) );
    290 
    291                     UserListingToImport::update_user_listing_item_import_status( array( $item->meli_listing_id ), 'finished' );
    292 
    293                     // Commit the transaction if everything is successful for this item
    294                     $wpdb->query( 'COMMIT' );
    295                 } catch ( \Exception $itemException ) {
    296                     // Log individual item error and rollback transaction
    297                     Helper::logData( 'Error processing listing id ' . $item->meli_listing_id . ': ' . $itemException->getMessage(), 'custom-import' );
    298 
    299                     // Rollback the transaction for the current item
    300                     $wpdb->query( 'ROLLBACK' );
    301                 }
    302             }
    303         } catch ( \Exception $e ) {
    304             // Log the error message
    305             Helper::logData( 'Error during custom import: ' . $e->getMessage(), 'custom-import' );
    306         } finally {
    307 
    308             UserListingToImport::update_vinculated_product_ids( $meli_listing_ids_arr );
    309             // When cron finishes, remove lock
    310             delete_option( $this->custom_import_lock_option_name );
    311 
    312             // Helper::logData('Custom import process finished. Deleting meliconnect_import_cancel_requested', 'custom-import');
    313 
    314             // Remove the cancel request flag
    315             delete_option( 'meliconnect_import_cancel_requested' );
    316         }
    317     }
     233        global $wpdb;
     234
     235        $lock_name = $this->custom_import_lock_option_name;
     236        $lock_ttl  = 300; // 5 minutos
     237        $batch_size = 20;
     238
     239        $processed_listing_ids = [];
     240        $lock_acquired = false;
     241
     242        Helper::logData(
     243            'CUSTOM IMPORT CRON START PID ' . getmypid(),
     244            'custom-import'
     245        );
     246
     247        try {
     248
     249            /**
     250             * LOCK CON TTL
     251             */
     252            $existing_lock = get_option($lock_name);
     253            if ( $existing_lock && ( time() - $existing_lock ) > $lock_ttl ) {
     254                delete_option($lock_name); // lock vencido
     255            }
     256
     257            $lock_acquired = add_option($lock_name, time(), '', 'no');
     258            if ( ! $lock_acquired ) {
     259                Helper::logData('Custom import already running. Exit.', 'custom-import');
     260                return;
     261            }
     262
     263            /**
     264             * OBTENER BATCH
     265             */
     266            $items = ProcessItems::getPendingBatch('custom-import', $batch_size);
     267
     268            if ( empty($items) ) {
     269                Helper::logData('No pending items. Import finished.', 'custom-import');
     270                return;
     271            }
     272
     273            /**
     274             * MARCAR COMO PROCESSING
     275             */
     276            $item_ids = wp_list_pluck($items, 'id');
     277            ProcessItems::markAsProcessing($item_ids);
     278
     279            $wooAdapter  = new WooCommerceProductAdapter();
     280            $creator     = new WooCommerceProductCreationService();
     281            $facade      = new ProductDataFacade($wooAdapter, $creator);
     282
     283            /**
     284             * PROCESAR BATCH
     285             */
     286            foreach ( $items as $item ) {
     287
     288                if ( get_option('meliconnect_import_cancel_requested') ) {
     289                    Helper::logData('Custom import canceled by user.', 'custom-import');
     290                    break;
     291                }
     292
     293                Helper::logData(
     294                    'Processing listing ' . $item->meli_listing_id,
     295                    'custom-import'
     296                );
     297
     298                try {
     299                    $wpdb->query('START TRANSACTION');
     300
     301                    $facade->importAndCreateProduct(
     302                        $item->meli_listing_id,
     303                        $item->meli_user_id,
     304                        $item->template_id,
     305                        $item->woo_product_id
     306                    );
     307
     308                    ProcessItems::markAsProcessed($item->id, $item->process_id);
     309
     310                    UserListingToImport::update_user_listing_item_import_status(
     311                        [$item->meli_listing_id],
     312                        'finished'
     313                    );
     314
     315                    $processed_listing_ids[] = $item->meli_listing_id;
     316
     317                    $wpdb->query('COMMIT');
     318
     319                } catch ( \Throwable $e ) {
     320
     321                    $wpdb->query('ROLLBACK');
     322
     323                    ProcessItems::markAsFailed(
     324                        $item->id,
     325                        $item->process_id,
     326                        $e->getMessage()
     327                    );
     328
     329                    UserListingToImport::update_user_listing_item_import_status(
     330                        [$item->meli_listing_id],
     331                        'failed'
     332                    );
     333
     334                    Helper::logData(
     335                        'Error listing ' . $item->meli_listing_id . ': ' . $e->getMessage(),
     336                        'custom-import'
     337                    );
     338                }
     339            }
     340
     341        } catch ( \Throwable $e ) {
     342           
     343
     344            Helper::logData(
     345                'Fatal import error: ' . $e->getMessage(),
     346                'custom-import'
     347            );
     348
     349        } finally {
     350
     351            if ( $lock_acquired ) {
     352                delete_option($lock_name);
     353            }
     354
     355            delete_option('meliconnect_import_cancel_requested');
     356
     357            if ( ! empty($processed_listing_ids) ) {
     358                UserListingToImport::update_vinculated_product_ids(
     359                    $processed_listing_ids
     360                );
     361            }
     362
     363            Helper::logData(
     364                'CUSTOM IMPORT CRON END',
     365                'custom-import'
     366            );
     367        }
     368    }
    318369
    319370    public function processUserCustomExport() {
  • meliconnect/trunk/includes/Core/Helpers/Helper.php

    r3408382 r3439817  
    4141        return $product_id ? (int) $product_id : null;
    4242    }
     43
     44
     45    public static function canSetSku( $sku, $variation_id = null ) {
     46
     47        $sku = trim( (string) $sku );
     48
     49        if ( $sku === '' ) {
     50            return false;
     51        }
     52
     53        $existing_id = wc_get_product_id_by_sku( $sku );
     54
     55        if ( ! $existing_id ) {
     56            return true;
     57        }
     58
     59        // Permitir si es la misma variación (update)
     60        if ( $variation_id && (int) $existing_id === (int) $variation_id ) {
     61            return true;
     62        }
     63
     64        return false;
     65    }
     66
    4367
    4468
     
    89113        // Construir y devolver la URL base
    90114        return "$scheme://$host"; */
     115
     116        if ( defined( 'WP_CLI' ) || php_sapi_name() === 'cli' ) {
     117            $_SERVER['HTTPS'] = 'on';
     118        }
    91119
    92120        return get_site_url();
     
    500528
    501529    public static function handleDismissNotifications() {
    502         global $wpdb;
     530        global $wpdb;
    503531
    504532        if ( ! isset( $_POST['nonce'] ) || ! wp_verify_nonce( sanitize_text_field( wp_unslash( $_POST['nonce'] ) ), 'meliconnect_notifications_nonce' ) ) {
  • meliconnect/trunk/includes/Core/Models/ProcessItems.php

    r3367389 r3439817  
    1616    }
    1717
    18     public static function updateProcessedItemStatus( $item_process_id, $status, $process_id ) {
     18    public static function getPendingBatch( string $type, int $limit ) {
     19        global $wpdb;
     20
     21        $process = Process::getCurrentProcessData( $type, array( 'pending', 'processing' ) );
     22
     23        if ( ! $process ) {
     24            return array();
     25        }
     26
     27        return self::getProcessItems(
     28            $process->process_id,
     29            $limit,
     30            'pending'
     31        );
     32    }
     33
     34    public static function markAsProcessing( array $ids ) {
     35        global $wpdb;
     36
     37        if ( empty( $ids ) ) {
     38            return;
     39        }
     40
     41        $placeholders = implode( ',', array_fill( 0, count( $ids ), '%d' ) );
     42
     43        $wpdb->query(
     44            $wpdb->prepare(
     45                "UPDATE {$wpdb->prefix}meliconnect_process_items
     46                SET status = 'processing', updated_at = NOW()
     47                WHERE id IN ($placeholders)",
     48                $ids
     49            )
     50        );
     51    }
     52
     53    public static function markAsProcessed( $item_id, $process_id ) {
     54        return self::updateProcessedItemStatus(
     55            $item_id,
     56            'processed',
     57            $process_id
     58        );
     59    }
     60
     61    public static function markAsFailed( $item_id, $process_id, $error ) {
     62        //Updates count of failed items in process table
     63        self::updateProcessedItemStatus(
     64            $item_id,
     65            'failed',
     66            $process_id
     67        );
     68       
     69        global $wpdb;
     70
     71        $wpdb->update(
     72            "{$wpdb->prefix}meliconnect_process_items",
     73            array(
     74                'process_status' => 'failed',
     75                'process_error'  => substr( $error, 0, 255 ),
     76                'updated_at'     => current_time( 'mysql' ),
     77            ),
     78            array(
     79                'id'         => $item_id,
     80                'process_id' => $process_id,
     81            )
     82        );
     83    }
     84
     85    public static function updateProcessedItemStatus( $item_process_id, $status, $process_id) {
    1986        global $wpdb;
    2087
     
    2895        if ( $result_item !== false ) {
    2996
    30             // update Process
    31             $process = Process::updateProcessProgress( $process_id, true );
     97            if ( $status == 'failed' ) {
     98                $process = Process::updateProcessProgress( $process_id, false );
     99            } else {
     100                $process = Process::updateProcessProgress( $process_id, true );
     101            }
    32102
    33103            return $process;
  • meliconnect/trunk/includes/Core/Models/Template.php

    r3367389 r3439817  
    760760            return false;
    761761        }
    762         Helper::logData( 'variation attrs' );
     762        //Helper::logData( 'variation attrs' );
    763763        foreach ( $meli_listing_data->variations as $variation ) {
    764764            $meli_variation_id = $variation->id;
  • meliconnect/trunk/includes/Modules/Importer/Assets/Js/meliconnect-importer.js

    r3367389 r3439817  
    22
    33    $('#action-to-do').select2();
     4
     5    $(document).on('click', '.meliconnect-remove-filter', function (e) {
     6        e.preventDefault();
     7
     8        const $tag = $(this).closest('.meliconnect-control');
     9
     10        $tag.fadeOut(150, function () {
     11            const filterKey = $tag.find('.meliconnect-remove-filter').data('filter');
     12            console.log(filterKey);
     13            const url = new URL(window.location.href);
     14            console.log(url);
     15
     16            url.searchParams.delete(filterKey);
     17            url.searchParams.delete('paged');
     18
     19            window.location.href = url.toString();
     20        });
     21    });
    422
    523    $('.match-all-listings-with-products').on('click', function (e) {
     
    4058            },
    4159            complete: function () {
    42                 // Remover las clases 'disabled' e 'is-loading' cuando la solicitud AJAX termine
     60                // Remover las clases 'disabled' e 'meliconnect-is-loading' cuando la solicitud AJAX termine
    4361                $button.removeClass('disabled meliconnect-is-loading');
    4462            }
     
    140158            processData: false,
    141159            beforeSend: function () {
    142                 $('#meliconnect-get-meli-user-listings-button').addClass('is-loading');
     160                $('#meliconnect-get-meli-user-listings-button').addClass('meliconnect-is-loading');
    143161            },
    144162            success: function (response) {
     
    154172                });
    155173       
    156                 $('#meliconnect-get-meli-user-listings-button').removeClass('is-loading');
     174                $('#meliconnect-get-meli-user-listings-button').removeClass('meliconnect-is-loading');
    157175            },
    158176            error: function (xhr, status, error) {
     
    164182                });
    165183       
    166                 $('#meliconnect-get-meli-user-listings-button').removeClass('is-loading');
     184                $('#meliconnect-get-meli-user-listings-button').removeClass('meliconnect-is-loading');
    167185            }
    168186        });
     
    315333                    data: {
    316334                        action: 'meliconnect_init_import_process',
    317                         nonce: meliconnect_translations.init_import_process_nonce
     335                        nonce: meliconnect_translations.init_import_process_nonce,
     336                        filters: window.location.search
    318337                    },
    319338                    success: function (response) {
  • meliconnect/trunk/includes/Modules/Importer/Controllers/ImportController.php

    r3372090 r3439817  
    274274        }
    275275
    276         self::initImportProcess();
     276         $filters = [];
     277
     278        if ( ! empty( $_POST['filters'] ) ) {
     279            parse_str( ltrim( $_POST['filters'], '?' ), $filters );
     280        }
     281
     282       
     283
     284        self::initImportProcessFiltered($filters);
    277285
    278286        wp_send_json_success();
     
    315323        }
    316324
    317         // UserListingToImport::cancel_import_process();
     325        UserListingToImport::update_processing_listings('pending');
    318326
    319327        update_option( 'meliconnect_import_cancel_requested', true );
     
    592600    }
    593601
     602    public static function initImportProcessFiltered( array $filters ) {
     603
     604        $items = UserListingToImport::get_user_listings_to_import_filtered( $filters );
     605
     606        if ( empty( $items ) ) {
     607            Helper::logData( 'No items found to import', 'initImportProcessFiltered' );
     608            return false;
     609        }
     610
     611        /* global $wpdb;
     612        echo PHP_EOL . '-------------------- last query --------------------' . PHP_EOL;
     613        echo '<pre>' . var_export(  $wpdb->last_query, true) . '</pre>';
     614        echo PHP_EOL . '-------------------  FINISHED  ---------------------' . PHP_EOL;
     615        echo PHP_EOL . '-------------------- items --------------------' . PHP_EOL;
     616        echo '<pre>' . var_export( count( $items ), true) . '</pre>';
     617        echo PHP_EOL . '-------------------  FINISHED  ---------------------' . PHP_EOL; */
     618
     619        $formatedItems = [];
     620
     621        foreach ( $items as $item ) {
     622            $formatedItems[] = [
     623                'meli_user_id'    => $item->meli_user_id,
     624                'meli_listing_id' => $item->meli_listing_id,
     625                'woo_product_id'  => $item->vinculated_product_id,
     626                'template_id'     => $item->vinculated_template_id,
     627                'process_status'  => 'processing',
     628            ];
     629        }
     630
     631        $process_id = Process::createProcess( 'custom-import', $formatedItems );
     632
     633        if ( ! $process_id ) {
     634            return false;
     635        }
     636
     637        $meli_listing_ids = array_column( $items, 'meli_listing_id' );
     638
     639       
     640
     641        UserListingToImport::update_user_listing_item_import_status(
     642            $meli_listing_ids,
     643            'processing'
     644        );
     645
     646        return true;
     647    }
     648
    594649    public static function multiGetListingsData( $seller_data, $meli_user_listings_ids ) {
    595650        $meli_user_listings_ids_chunk = array_chunk( $meli_user_listings_ids, 20 );
     
    645700        $base_url = 'users/' . $seller_data->user_id . '/items/search?search_type=scan';
    646701        $items    = MeliconMeli::getWithHeader( $base_url, $seller_data->access_token );
    647         echo PHP_EOL . '-------------------- $items --------------------' . PHP_EOL;
    648         echo '<pre>' . var_export( $items, true) . '</pre>';
    649         echo PHP_EOL . '-------------------  FINISHED  ---------------------' . PHP_EOL;
     702
    650703        if ( ! isset( $items['body']->results ) || ! is_iterable( $items['body']->results ) ) {
    651704            Helper::logData( 'Error getting products from seller: ' . $seller_data->user_id, 'importer' );
  • meliconnect/trunk/includes/Modules/Importer/Models/UserListingToImport.php

    r3367389 r3439817  
    5959    public static function apply_item_manual_match( $meli_item_id, $woo_product_id ) {}
    6060
     61
     62
    6163    public static function update_meli_user_listings_extra_data_to_import( $meli_user_listings_data ) {
    6264        global $wpdb;
     
    9799                    'vinculated_product_id'  => $listing_data['vinculated_product_id'],
    98100                    'vinculated_template_id' => $listing_data['vinculated_template_id'],
     101                    'import_status'          => 'pending',
    99102                ),
    100103                array(
     
    161164        // phpcs:enable
    162165    }
     166
     167    public static function get_user_listings_to_import_filtered( array $filters ) {
     168        global $wpdb;
     169        self::init();
     170
     171        $table_name = self::$table_name;
     172        $where      = [];
     173        $params     = [];
     174
     175        // Solo pendientes
     176        $where[] = "(import_status = 'pending' )";
     177
     178        // Search
     179        if ( ! empty( $filters['search'] ) ) {
     180            $where[] = "(meli_listing_title LIKE %s OR meli_listing_id LIKE %s OR meli_sku LIKE %s)";
     181            $search  = '%' . $wpdb->esc_like( $filters['search'] ) . '%';
     182
     183            $params[] = $search;
     184            $params[] = $search;
     185            $params[] = $search;
     186        }
     187
     188        // Seller
     189        if ( ! empty( $filters['seller'] ) ) {
     190            $where[]  = "meli_user_id = %d";
     191            $params[] = (int) $filters['seller'];
     192        }
     193
     194        // Vinculation
     195        if ( ! empty( $filters['vinculation_filter'] ) ) {
     196
     197            if ( $filters['vinculation_filter'] === 'no_product' ) {
     198                $where[] = "(vinculated_product_id IS NULL OR vinculated_product_id = 0)";
     199            }
     200
     201            if ( $filters['vinculation_filter'] === 'yes_product' ) {
     202                $where[] = "(vinculated_product_id IS NOT NULL AND vinculated_product_id > 0)";
     203            }
     204        }
     205
     206        // Status
     207        if ( ! empty( $filters['listing_status_filter'] ) ) {
     208            $where[]  = "meli_status = %s";
     209            $params[] = $filters['listing_status_filter'];
     210        }
     211
     212        // Listing type
     213        if ( ! empty( $filters['listing_type_filter'] ) ) {
     214            $where[]  = "meli_product_type = %s";
     215            $params[] = $filters['listing_type_filter'];
     216        }
     217
     218        $sql = "SELECT * FROM {$table_name}";
     219
     220        if ( $where ) {
     221            $sql .= ' WHERE ' . implode( ' AND ', $where );
     222        }
     223
     224
     225
     226        // phpcs:disable WordPress.DB.PreparedSQL.NotPrepared
     227        return $params
     228            ? $wpdb->get_results( $wpdb->prepare( $sql, ...$params ) )
     229            : $wpdb->get_results( $sql );
     230        // phpcs:enable
     231    }
    163232
    164233
  • meliconnect/trunk/includes/Modules/Importer/Services/WooCommerceProductAdapter.php

    r3367389 r3439817  
    4949        $server_response = $this->sendDataToServer( $rawData );
    5050
    51         Helper::logData('Server response:' . $server_response, 'custom-import');
     51        //Helper::logData('Server response:' . $server_response, 'custom-import');
    5252
    5353        return json_decode( $server_response, true );
  • meliconnect/trunk/includes/Modules/Importer/Services/WooCommerceProductCreationService.php

    r3372090 r3439817  
    5858            }
    5959
     60            Helper::logData( 'Product type: ' . $product_data['type'], 'custom-import' );
     61
    6062            // Create a product with basic data and saves it
    6163            $woo_product = $this->createBaseProduct( $woo_product, $product_data );
     
    115117        Helper::logData( 'Woo Product id: ' . $woo_product->get_id(), 'custom-import' );
    116118
    117         Helper::logData( 'Product data: ' . wp_json_encode( $product_data ), 'custom-import' );
     119        //Helper::logData( 'Product data: ' . wp_json_encode( $product_data ), 'custom-import' );
     120
     121        $meli_seller_id = $product_data['extra_data']['postmetas']['meliconnect_meli_seller_id'] ?? null;
    118122
    119123        // Asignar el título del producto
     
    127131            // Verificar si el SKU ya existe
    128132            $existing_product_id = Helper::get_active_product_id_by_sku( $product_data['sku'] );
     133            if ( $sku ) {
     134                update_post_meta(
     135                    $woo_product->get_id(),
     136                    '_meliconnect_sku',
     137                    $product_data['sku']
     138                );
     139            }
    129140
    130141            if ( $existing_product_id ) {
     
    141152
    142153        if ( isset( $product_data['gtin'] ) && $product_data['gtin'] !== false ) {
    143             $woo_product->set_global_unique_id( $product_data['gtin'] );
    144             Helper::logData( 'GTIN: ' . $product_data['gtin'], 'custom-import' );
     154           
     155            Helper::logData( 'GTIN: ' . $product_data['gtin'], 'custom-import' );
     156
     157
     158            //Because GTIN is validated by woocommerce, we need to save it as a postmeta
     159            //$woo_product->set_global_unique_id( $product_data['gtin'] );
     160
     161            update_post_meta(
     162                $woo_product->get_id(),
     163                '_meliconnect_gtin',
     164                $product_data['gtin']
     165            );
     166           
    145167        } else {
    146168            Helper::logData( 'GTIN ignored by settings', 'custom-import' );
    147169        }
     170
    148171
    149172        // Descripciones
     
    197220        // Imágenes
    198221        if ( isset( $product_data['pictures']['main_image'] ) && $product_data['pictures']['main_image'] !== false ) {
    199             $this->create_or_update_main_image( $woo_product->get_id(), $product_data['pictures']['main_image'] );
     222            $this->create_or_update_main_image( $woo_product->get_id(), $product_data['pictures']['main_image'], $meli_seller_id );
    200223        } else {
    201224            Helper::logData( 'Main image ignored by settings', 'custom-import' );
     
    203226
    204227        if ( isset( $product_data['pictures']['gallery_images'] ) && $product_data['pictures']['gallery_images'] !== false ) {
    205             $this->create_or_update_gallery_images( $woo_product->get_id(), $product_data['pictures']['gallery_images'] );
     228            $this->create_or_update_gallery_images( $woo_product->get_id(), $product_data['pictures']['gallery_images'], $meli_seller_id );
    206229        } else {
    207230            Helper::logData( 'Gallery images ignored by settings', 'custom-import' );
     
    305328
    306329            $variation->set_regular_price( $variation_data['price'] );
    307             $variation->set_sku( $variation_data['sku'] );
     330           
     331            $sku = trim( $variation_data['sku'] ) ?? '';
     332
     333            if ( $sku ) {
     334                update_post_meta(
     335                    $existing_variation_id ,
     336                    '_meliconnect_sku',
     337                    $sku
     338                );
     339            }
     340
     341            if ( Helper::canSetSku( $sku, $existing_variation_id ) ) {
     342               
     343                $variation->set_sku( $sku );
     344 
     345            } else {
     346                Helper::logData(
     347                    'Variation SKU skipped because it already exists. SKU="' . $sku . '" Product=' . $product_id,
     348                    'custom-import'
     349                );
     350            }
     351
    308352            $variation->set_stock_quantity( $variation_data['available_quantity'] );
    309353            $variation->set_manage_stock( $variation_data['manage_stock'] );
     
    358402            }
    359403        }
    360 
    361         // Asignar SKU y registrar
    362         if ( $sku ) {
    363             $variation->set_sku( $sku );
    364             // Helper::logData('Assigned SKU: ' . $sku, 'custom-import');
    365         }
     404       
     405        if ( $sku ) {
     406            update_post_meta(
     407                $variation->get_id()  ,
     408                '_meliconnect_sku',
     409                $sku
     410            );
     411        }
     412
     413        if ( Helper::canSetSku( $sku, $variation->get_id() ) ) {
     414               
     415            $variation->set_sku( $sku );
     416
     417            Helper::logData('Assigned SKU from Meli attribute: ' . $sku, 'custom-import');
     418 
     419        } else {
     420            Helper::logData(
     421                'Variation Attr SKU skipped because it already exists. SKU="' . $sku . '" Variation ID =' . $variation->get_id() ,
     422                'custom-import'
     423            );
     424        }
    366425
    367426        // Guardar GTIN como postmeta y registrar resultado
     
    369428            $result = update_post_meta( $variation->get_id(), '_global_unique_id', $gtin );
    370429            if ( $result === false ) {
    371                 // Helper::logData('Failed to update GTIN for variation ID ' . $variation->get_id(), 'custom-import');
    372             } else {
    373                 // Helper::logData('Successfully updated GTIN for variation ID ' . $variation->get_id(), 'custom-import');
     430                Helper::logData('Failed to update GTIN for variation ID ' . $variation->get_id(), 'custom-import');
     431            } else {
     432                Helper::logData('Successfully updated GTIN for variation ID ' . $variation->get_id(), 'custom-import');
    374433            }
    375434        }
     
    581640
    582641
    583     private function create_or_update_main_image( $post_id, $main_image_data ) {
     642    private function create_or_update_main_image( $post_id, $main_image_data, $seller_id = null ) {
    584643        // Extraer el ID de la imagen
    585644        $image_id = $main_image_data['id'];
    586645
    587         $seller_id = get_post_meta( $post_id, 'meliconnect_meli_seller_id', true );
     646        if(empty($seller_id)){
     647            $seller_id = get_post_meta( $post_id, 'meliconnect_meli_seller_id', true );
     648        }
     649       
    588650        $access_token = UserConnection::get_meli_access_token_by_seller( $seller_id );
    589651
     
    745807
    746808
    747     private function create_or_update_gallery_images( $post_id, $gallery_images_data ) {
     809    private function create_or_update_gallery_images( $post_id, $gallery_images_data , $meli_seller_id =null ) {
    748810        $gallery_ids    = array();
    749         $meli_seller_id = get_post_meta( $post_id, 'meliconnect_meli_seller_id', true );
     811
     812        if(empty($meli_seller_id)){
     813            $meli_seller_id = get_post_meta( $post_id, 'meliconnect_meli_seller_id', true );   
     814        }
     815       
    750816
    751817        foreach ( $gallery_images_data as $image_data ) {
  • meliconnect/trunk/includes/Modules/Importer/Views/importer.php

    r3372090 r3439817  
    44    exit; // Exit if accessed directly
    55}
     6
     7use Meliconnect\Meliconnect\Core\Helpers\Helper;
    68use Meliconnect\Meliconnect\Modules\Importer\Controllers\ImportController;
    79
     
    1416require MELICONNECT_PLUGIN_ROOT . 'includes/Core/Views/Partials/header.php';
    1517
     18// phpcs:disable WordPress.Security.NonceVerification.Recommended -- Solo lectura de parámetros de URL.
     19$search_value            = isset( $_GET['search'] ) ? sanitize_text_field( wp_unslash( $_GET['search'] ) ) : '';
     20$selected_vinculation    = isset( $_GET['vinculation_filter'] ) ? sanitize_text_field( wp_unslash( $_GET['vinculation_filter'] ) ) : '';
     21$selected_listing_status = isset( $_GET['listing_status_filter'] ) ? sanitize_text_field( wp_unslash( $_GET['listing_status_filter'] ) ) : '';
     22$selected_template       = isset( $_GET['template_filter'] ) ? sanitize_text_field( wp_unslash( $_GET['template_filter'] ) ) : '';
     23$selected_listing_type   = isset( $_GET['listing_type_filter'] ) ? sanitize_text_field( wp_unslash( $_GET['listing_type_filter'] ) ) : '';
     24$selected_seller         = isset( $_GET['seller_filter'] ) ? sanitize_text_field( wp_unslash( $_GET['seller_filter'] ) ) : '';
     25
     26$total_filtered_items = Meliconnect\Meliconnect\Modules\Importer\UserListingsTable::record_count();
     27
     28
     29// phpcs:enable WordPress.Security.NonceVerification.Recommended
    1630?>
     31
     32
    1733<!-- START MCSYNCAPP -->
    1834<div id="meliconnect-page-importer-main" class="meliconnect-app">
     
    2137            <?php if ( ! empty( $data['sellers_exceeding_limit'] ) ) : ?>
    2238                <div class="meliconnect-notification meliconnect-is-warning meliconnect-is-light">
    23                     <button class="meliconnect-delete"></button>   
    24                     <p>
    25                         <i class="fas fa-exclamation-triangle"></i>
     39                    <button class="meliconnect-delete"></button>   
     40                    <p>
     41                        <i class="fas fa-exclamation-triangle"></i>
    2642                        <?php
    2743                            printf(
     
    110126                            </div>
    111127
    112                             <div style="display: flex;">
     128                            <div style="display: flex;" class="meliconnect-is-hidden-touch">
    113129                                <div style="flex: 1;height: 100px; background-color: #f4f5f8"></div>
    114130                                <div class="divider meliconnect-is-vertical"> >> </div>
     
    164180                            </div>
    165181
    166                             <div style="display: flex;">
     182                            <div style="display: flex;" class="meliconnect-is-hidden-touch">
    167183                                <div style="flex: 1;height: 100px; background-color: #f4f5f8"></div>
    168                                 <div class="divider meliconnect-is-vertical"> >> </div>
     184                                <div class="divider meliconnect-is-vertical is-hidden-touch"> >> </div>
    169185                                <div style="flex: 1;height: 100px; background-color: #f4f5f8"></div>
    170186                            </div>
     
    189205                                <form class="is-flex meliconnect-is-flex-direction-column" id="meliconnect-get-meli-user-listings" method="POST">
    190206                                    <div class="meliconnect-field mb-3">
    191                                         <label class="meliconnect-label"><?php esc_html_e( 'Select seller', 'meliconnect' ); ?></label>
     207                                        <label class="meliconnect-label"><?php esc_html_e( 'Seller', 'meliconnect' ); ?></label>
    192208
    193209                                        <?php
     
    214230                            if ( $data['meli_user_listings_to_import_count'] > 0 ) {
    215231                                ?>
    216                                 <div style="display: flex;">
     232                                <div style="display: flex;" class="meliconnect-is-hidden-touch">
    217233                                    <div style="flex: 1;height: 100px; background-color: #f4f5f8"></div>
    218234                                    <div class="divider meliconnect-is-vertical"> > </div>
     
    237253                                </div>
    238254
    239                                 <div style="display: flex;">
     255                                <div style="display: flex;" class="meliconnect-is-hidden-touch">
    240256                                    <div style="flex: 1;height: 100px; background-color: #f4f5f8"></div>
    241257                                    <div class="divider meliconnect-is-vertical"> >> </div>
     
    245261                                <!-- Buttons Column -->
    246262                                <div class="meliconnect-column meliconnect-is-3">
    247                                     <p><strong><?php esc_html_e( 'Mercadolibre', 'meliconnect' ); ?></strong> </p>
    248                                     <p><?php esc_html_e( 'Total active items', 'meliconnect' ); ?> :
    249                                         <span id="meliconnect-import-seller-total-items-active">
    250                                             <?php echo esc_html( $data['meli_user_listings_active_to_import_count'] ); ?>
     263                                    <p><strong><?php esc_html_e( 'Active filters', 'meliconnect' ); ?></strong></p>
     264
     265                                    <?php
     266                                    $active_filters = array();
     267
     268                                    // Search
     269                                    if ( $search_value ) {
     270                                        $active_filters['s'] = array(
     271                                            'name'  => 'search',
     272                                            'label' => __( 'Search', 'meliconnect' ),
     273                                            'value' => $search_value,
     274                                        );
     275                                    }
     276
     277                                    // Vinculation
     278                                    if ( $selected_vinculation ) {
     279
     280                                        if ( $selected_vinculation == 'yes_product' ) {
     281                                            $selected_vinculation_text = 'To update';
     282                                        } elseif ( $selected_vinculation == 'no_product' ) {
     283                                            $selected_vinculation_text = 'To create';
     284                                        }
     285
     286                                        $active_filters['vinculation'] = array(
     287                                            'name'  => 'vinculation_filter',
     288                                            'label' => __( 'Action', 'meliconnect' ),
     289                                            'value' => ucfirst( str_replace( '_', ' ', $selected_vinculation_text ) ),
     290                                        );
     291                                    }
     292
     293                                    // Status
     294                                    if ( $selected_listing_status ) {
     295                                        $active_filters['status'] = array(
     296                                            'name'  => 'listing_status_filter',
     297                                            'label' => __( 'Status', 'meliconnect' ),
     298                                            'value' => ucfirst( str_replace( '_', ' ', $selected_listing_status ) ),
     299                                        );
     300                                    }
     301
     302                                    // Type
     303                                    if ( $selected_listing_type ) {
     304                                        $active_filters['type'] = array(
     305                                            'name'  => 'listing_type_filter',
     306                                            'label' => __( 'Type', 'meliconnect' ),
     307                                            'value' => ucfirst( $selected_listing_type ),
     308                                        );
     309                                    }
     310
     311                                    // Seller
     312                                    if ( $selected_seller ) {
     313                                        $active_filters['seller'] = array(
     314                                            'name'  => 'seller_filter',
     315                                            'label' => __( 'Seller', 'meliconnect' ),
     316                                            'value' => $selected_seller,
     317                                        );
     318                                    }
     319                                    ?>
     320
     321                                    <?php if ( empty( $active_filters ) ) : ?>
     322
     323                                        <p class="has-text-grey">
     324                                            <?php esc_html_e( 'No filters applied', 'meliconnect' ); ?>
     325                                        </p>
     326
     327                                    <?php else : ?>
     328
     329                                    <div class="meliconnect-field meliconnect-is-grouped meliconnect-is-grouped-multiline meliconnect-active-filters">
     330
     331                                        <?php foreach ( $active_filters as $key => $filter ) : ?>
     332                                            <div class="meliconnect-control">
     333                                                <div class="meliconnect-tags meliconnect-has-addons">
     334                                                    <span class="meliconnect-tag meliconnect-is-link">
     335                                                        <?php echo esc_html( $filter['value'] ); ?>
     336                                                    </span>
     337                                                    <a
     338                                                        href="#"
     339                                                        class="meliconnect-tag meliconnect-is-delete meliconnect-remove-filter"
     340                                                        data-filter="<?php echo esc_attr( $filter['name'] ); ?>">
     341                                                    </a>
     342                                                </div>
     343                                            </div>
     344                                        <?php endforeach; ?>
     345
     346                                    </div>
     347
     348                                    <?php endif; ?>
     349
     350                                    <div>
     351                                        <strong class="meliconnect-is-size-5"><?php esc_html_e( 'Total to import', 'meliconnect' ); ?> </strong> :
     352                                        <span id="meliconnect-products-to-process-total">
     353                                            <?php echo esc_html( $total_filtered_items ); ?>
    251354                                        </span>
    252                                     </p>
    253                                     <p><?php esc_html_e( 'Not active items', 'meliconnect' ); ?> :
    254                                         <span id="meliconnect-import-seller-total-items-not-actived">
    255                                             <?php echo esc_html( ( $data['meli_user_listings_to_import_count'] - $data['meli_user_listings_active_to_import_count'] ) ); ?>
    256                                         </span>
    257                                     </p>
    258 
    259                                     <p><strong><?php esc_html_e( 'Woocommerce', 'meliconnect' ); ?></strong> </p>
    260                                     <p>
    261                                         <?php esc_html_e( 'Vinculated Products', 'meliconnect' ); ?> :
    262                                         <span id="meliconnect-import-seller-total-products-vinculated">
    263                                             <?php echo esc_html( $data['woo_total_vinculated_products'] ); ?>
    264                                         </span>
    265                                     </p>
    266                                     <p>
    267                                         <?php esc_html_e( 'Not Vinculated Products', 'meliconnect' ); ?> :
    268                                         <span id="meliconnect-import-seller-total-products-desvinculated">
    269                                             <?php echo esc_html( ( $data['woo_total_active_products'] - $data['woo_total_vinculated_products'] ) ); ?>
    270                                         </span>
    271                                     </p>
     355                                    </div>
    272356                                    <div class="meliconnect-control meliconnect-mt-4">
    273357                                        <button id="meliconnect-process-import-button" class="meliconnect-button meliconnect-is-success  meliconnect-is-fullwidth">
     
    300384                                        <div class="meliconnect-columns ">
    301385                                            <div class="meliconnect-column">
    302                                                 <?php
    303                                                 // phpcs:disable WordPress.Security.NonceVerification.Recommended -- Solo lectura de parámetros de URL.
    304                                                 $search_value            = isset( $_GET['search'] ) ? sanitize_text_field( wp_unslash( $_GET['search'] ) ) : '';
    305                                                 $selected_vinculation    = isset( $_GET['vinculation_filter'] ) ? sanitize_text_field( wp_unslash( $_GET['vinculation_filter'] ) ) : '';
    306                                                 $selected_listing_status = isset( $_GET['listing_status_filter'] ) ? sanitize_text_field( wp_unslash( $_GET['listing_status_filter'] ) ) : '';
    307                                                 $selected_template       = isset( $_GET['template_filter'] ) ? sanitize_text_field( wp_unslash( $_GET['template_filter'] ) ) : '';
    308                                                 $selected_listing_type   = isset( $_GET['listing_type_filter'] ) ? sanitize_text_field( wp_unslash( $_GET['listing_type_filter'] ) ) : '';
    309                                                 $selected_seller         = isset( $_GET['seller_filter'] ) ? sanitize_text_field( wp_unslash( $_GET['seller_filter'] ) ) : '';
    310                                                 // phpcs:enable WordPress.Security.NonceVerification.Recommended
    311                                                 ?>
     386                                               
    312387                                                <div class="meliconnect-field meliconnect-has-addons">
    313388                                                    <div class="meliconnect-control">
     
    318393                                                        <div class="meliconnect-select meliconnect-is-fullwidth">
    319394                                                            <select class="meliconnect-select" name="vinculation_filter">
    320                                                                 <option value=""><?php esc_html_e( 'All Vinculations', 'meliconnect' ); ?></option>
    321                                                                 <option value="yes_product" <?php selected( $selected_vinculation, 'yes_product' ); ?>><?php esc_html_e( 'With Vinculated Product', 'meliconnect' ); ?></option>
    322                                                                 <option value="no_product" <?php selected( $selected_vinculation, 'no_product' ); ?>><?php esc_html_e( 'Without Vinculated Product', 'meliconnect' ); ?></option>
     395                                                                <option value=""><?php esc_html_e( 'To update or create', 'meliconnect' ); ?></option>
     396                                                                <option value="yes_product" <?php selected( $selected_vinculation, 'yes_product' ); ?>><?php esc_html_e( 'Only to update', 'meliconnect' ); ?></option>
     397                                                                <option value="no_product" <?php selected( $selected_vinculation, 'no_product' ); ?>><?php esc_html_e( 'Only to create', 'meliconnect' ); ?></option>
    323398                                                                <!-- <option value="yes_template" <?php selected( $selected_template, 'yes_template' ); ?>><?php esc_html_e( 'With Vinculated Template', 'meliconnect' ); ?></option>
    324399                                                                <option value="no_template" <?php selected( $selected_template, 'no_template' ); ?>><?php esc_html_e( 'Without Vinculated Template', 'meliconnect' ); ?></option> -->
     
    347422                                                    </div>
    348423
     424                                                    <?php
     425
     426                                                    $sellers = Helper::getSellersIdsAndNames();
     427
     428                                                    if ( empty( $sellers ) && is_iterable( $sellers ) && count( $sellers ) > 1 ) {
     429
     430                                                        ?>
     431
    349432                                                    <div class="meliconnect-control meliconnect-is-expanded">
    350433                                                        <div class="meliconnect-select meliconnect-is-fullwidth">
     
    357440                                                        </div>
    358441                                                    </div>
     442                                                   
     443                                                    <?php } ?>
    359444
    360445                                                    <div class="meliconnect-control">
  • meliconnect/trunk/meliconnect.php

    r3408382 r3439817  
    44Plugin URI: https://mercadolibre.meliconnect.com/
    55Description: WooCommerce & Mercado Libre integration to import, export, and synchronize products between your WooCommerce store and Mercado Libre accounts.
    6 Version: 1.3.2
     6Version: 1.4.0
    77Author: meliconnect
    88Text Domain: meliconnect
     
    2626 * Define constantes del plugin
    2727 */
    28 define( 'MELICONNECT_VERSION', '1.3.2' );
     28define( 'MELICONNECT_VERSION', '1.4.0' );
    2929define( 'MELICONNECT_DATABASE_VERSION', '1.1.1' );
    3030define( 'MELICONNECT_TEXTDOMAIN', 'meliconnect' );
  • meliconnect/trunk/readme.txt

    r3408382 r3439817  
    55Requires at least: 5.8
    66Requires PHP:    8.0
    7 Tested up to: 6.8
    8 Stable tag: 1.3.2
     7Tested up to: 6.9
     8Stable tag: 1.4.0
    99License: GPLv3
    1010License URI: https://www.gnu.org/licenses/gpl-3.0.html
  • meliconnect/trunk/vendor/composer/installed.php

    r3408382 r3439817  
    44        'pretty_version' => 'dev-main',
    55        'version' => 'dev-main',
    6         'reference' => '79df82fcd1a40f7146c829825bb50a99eb01d76f',
     6        'reference' => 'e8b468faf960e6fd332bd847ae2f031be364d0b4',
    77        'type' => 'wordpress-plugin',
    88        'install_path' => __DIR__ . '/../../',
     
    1414            'pretty_version' => 'dev-main',
    1515            'version' => 'dev-main',
    16             'reference' => '79df82fcd1a40f7146c829825bb50a99eb01d76f',
     16            'reference' => 'e8b468faf960e6fd332bd847ae2f031be364d0b4',
    1717            'type' => 'wordpress-plugin',
    1818            'install_path' => __DIR__ . '/../../',
Note: See TracChangeset for help on using the changeset viewer.