Plugin Directory

Changeset 3301423


Ignore:
Timestamp:
05/27/2025 11:13:07 AM (10 months ago)
Author:
closetechnology
Message:

Update to version 3.1.0 from GitHub

Location:
connect-ecommerce
Files:
4 added
4 deleted
26 edited
1 copied

Legend:

Unmodified
Added
Removed
  • connect-ecommerce/tags/3.1.0/connect-ecommerce.php

    r3289663 r3301423  
    66 * Author: Closetechnology
    77 * Author URI: https://close.technology/
    8  * Version: 3.0.1
     8 * Version: 3.1.0
    99 *
    1010 * @package WordPress
     
    1717defined( 'ABSPATH' ) || exit;
    1818
    19 define( 'CONECOM_VERSION', '3.0.1' );
     19define( 'CONECOM_VERSION', '3.1.0' );
    2020define( 'CONECOM_FILE', __FILE__ );
    2121define( 'CONECOM_PLUGIN_URL', plugin_dir_url( __FILE__ ) );
     
    2626require_once CONECOM_PLUGIN_PATH . 'vendor/autoload.php';
    2727
    28 add_action( 'init', 'conecom_loads' );
    29 /**
    30  * Connect WooCommerce loads.
    31  *
    32  * @return void
    33  */
    34 function conecom_loads() {
    35     /**
     28function conecom_get_options() {
     29        /**
    3630     * Default values
    3731     */
    3832    global $wpdb;
    3933
    40     $conecom_options = apply_filters(
     34    return apply_filters(
    4135        'conecom_options_plugin',
    4236        [
     
    114108        ]
    115109    );
     110}
    116111
     112
     113
     114add_action( 'init', 'conecom_loads' );
     115/**
     116 * Connect WooCommerce loads.
     117 *
     118 * @return void
     119 */
     120function conecom_loads() {
    117121    require_once CONECOM_PLUGIN_PATH . 'includes/Plugin_Main.php';
    118122    require_once CONECOM_PLUGIN_PATH . 'includes/Connector/class-api-clientify.php';
    119123
     124    $conecom_options = conecom_get_options();
    120125    new CLOSE\ConnectEcommerce\Base( $conecom_options );
    121126}
     127
     128if ( defined( 'WP_CLI' ) && WP_CLI ) {
     129    require_once CONECOM_PLUGIN_PATH . 'includes/CLI/Import_Products_Command.php';
     130
     131    /**
     132     * Registers our command when cli get's initialized.
     133     *
     134     * @since  1.0.0
     135     * @author David Perez
     136     */
     137    function conecom_import_products_register_commands() {
     138        WP_CLI::add_command('conecom', 'Import_Products_Command' );
     139    }
     140
     141    add_action( 'cli_init', 'conecom_import_products_register_commands', 20 );
     142}
  • connect-ecommerce/tags/3.1.0/includes/Admin/Import_Products.php

    r3281293 r3301423  
    174174        $product_erp_id = isset( $_POST['product_erp_id'] ) ? sanitize_text_field( wp_unslash( $_POST['product_erp_id'] ) ) : '';
    175175        $product_sku    = isset( $_POST['product_sku'] ) ? sanitize_text_field( wp_unslash( $_POST['product_sku'] ) ) : '';
     176        $product_id     = isset( $_POST['product_id'] ) ? (int) $_POST['product_id'] : '';
    176177        $message        = '';
    177178        $res_message    = '';
    178         $generate_ai    = isset( $_POST['product_ai'] ) ? sanitize_key( $_POST['product_ai'] ) : 'none';
     179        $generate_ai    = ! empty( $_POST['product_ai'] ) ? sanitize_key( $_POST['product_ai'] ) : 'none';
     180        $generate_ai    = 'true' === $generate_ai ? 'all' : $generate_ai;
    179181        $api_pagination = ! empty( $this->options['api_pagination'] ) ? $this->options['api_pagination'] : false;
    180182
     
    224226        $this->msg_error_products = array();
    225227
    226         $result_sync = PROD::sync_product_item( $this->settings, $item, $this->connapi_erp, $this->options['slug'], $generate_ai );
     228        $result_sync = PROD::sync_product_item( $this->settings, $item, $this->connapi_erp, $generate_ai, $product_id );
    227229        $post_id     = $result_sync['post_id'] ?? 0;
    228230        if ( 'error' === $result_sync['status'] ) {
     
    321323
    322324                $product_api = $this->connapi_erp->get_products( $product_id );
    323                 $result      = PROD::sync_product_item( $this->settings, $product_api, $this->connapi_erp, $this->options['slug'] );
     325                $result      = PROD::sync_product_item( $this->settings, $product_api, $this->connapi_erp );
    324326                if ( $is_table_sync ) {
    325327                    CRON::save_product_sync( $this->options['table_sync'], $result['prod_id'], $this->options['slug'] );
  • connect-ecommerce/tags/3.1.0/includes/Admin/Settings.php

    r3289663 r3301423  
    6767     */
    6868    private $connapi_erp;
    69 
    70     /**
    71      * Settings slug
    72      *
    73      * @var string
    74      */
    75     private $settings_slug;
    7669
    7770    /**
     
    544537                );
    545538            }
     539
     540            add_settings_field(
     541                'wcpimh_make_discount',
     542                __( 'Percentage to Make a discount from prices and save in sale price?', 'connect-ecommerce' ),
     543                array( $this, 'pricesale_discount_option_callback' ),
     544                'connect_ecommerce_admin',
     545                'connect_woocommerce_setting_section'
     546            );
    546547
    547548            if ( $this->options['product_price_rate_option'] ) {
     
    920921                'catattr'        => '',
    921922                'filter'         => '',
     923                'pricesale_discount' => '',
    922924                'filter_sku'     => '',
    923925                'tax_option'     => 'no',
     
    12651267        </select>
    12661268        <?php
     1269    }
     1270
     1271    /**
     1272     * Percentage price discount
     1273     *
     1274     * @return void
     1275     */
     1276    public function pricesale_discount_option_callback() {
     1277        printf(
     1278            '<input class="regular-text" type="text" name="connect_ecommerce[' . esc_html( $this->connector ) . '][pricesale_discount]" id="wcpimh_pricesale_discount" value="%s" style="width:60px">%%',
     1279            isset( $this->settings['pricesale_discount'] ) ? esc_attr( $this->settings['pricesale_discount'] ) : ''
     1280        );
    12671281    }
    12681282
  • connect-ecommerce/tags/3.1.0/includes/Admin/Widget_Product.php

    r3289663 r3301423  
    8787        echo '\'' . esc_html( $product_erp_id ) . '\',';
    8888        echo '\'' . esc_html( $product->get_sku() ) . '\',';
    89         echo 'this.id)">' . esc_html__( 'Sync', 'connect-ecommerce' ) . '</div>';
     89        echo '\'' . esc_html( $product_id ) . '\',';
     90        echo ')">' . esc_html__( 'Sync', 'connect-ecommerce' ) . '</div>';
    9091        echo '</td>';
    9192        echo '</tr>';
  • connect-ecommerce/tags/3.1.0/includes/Helpers/AI.php

    r3281293 r3301423  
    9797        );
    9898        $content .= PHP_EOL . __( 'Generate a Title, Content, Title SEO and SEO description and export it in format JSON, with elements: title, body, seo_title, seo_description', 'connect-ecommerce' );
     99        $content .= PHP_EOL . __( 'Return only a valid and complete JSON object. If the content is too long, split it into multiple parts and clearly indicate when to continue. Do not include any text outside of the JSON.', 'connect-ecommerce' );
    99100
    100101        $token = isset( $settings['token'] ) ? $settings['token'] : '';
     
    123124                'Authorization' => 'Bearer ' . $token,
    124125            ),
     126            'timeout' => 90,
    125127            'body'    => wp_json_encode(
    126128                array(
     
    136138                    'n'                 => 1,
    137139                    'stream'            => false,
    138                     'max_tokens'        => 250,
     140                    'max_tokens'        => 1024,
    139141                    'presence_penalty'  => 0,
    140142                    'frequency_penalty' => 0,
     
    145147        $response      = wp_remote_post( $api_url, $args );
    146148        $response_code = wp_remote_retrieve_response_code( $response );
    147         $response      = json_decode( wp_remote_retrieve_body( $response ), true );
     149        $body          = json_decode( wp_remote_retrieve_body( $response ), true );
    148150
    149151        if ( 200 !== $response_code ) {
     152            $message .= sanitize_text_field( $response['error']['message'] ) ?? '';
     153            $message .= sanitize_text_field( $response['errors']['http_request_failed'] ) ?? '';
     154            $message .= $message ?? __( 'Unknown error', 'connect-ecommerce' );
     155
    150156            return array(
    151                 'status'  => 0,
    152                 'message' => isset( $response['error']['message'] ) ? sanitize_text_field( $response['error']['message'] ) : __( 'Unknown error', 'connect-ecommerce' ),
     157                'status'  => 'error',
     158                'message' => $message,
    153159            );
    154160        }
    155161        $content = array();
    156         if ( isset( $response['choices'][0]['message']['content'] ) ) {
    157             $content = str_replace( '```json', '', $response['choices'][0]['message']['content'] );
    158             $content = str_replace( '```', '', $content );
     162        if ( isset( $body['choices'][0]['message']['content'] ) ) {
     163            error_log( '$content: ' . print_r( $body['choices'][0]['message']['content'], true ) );
     164            $content = str_replace( '```json', '', $body['choices'][0]['message']['content'] );
     165            $content = preg_replace( '/```[\w]*\s*/', '', $content );
     166            $content = trim( $content );
    159167            $content = json_decode( $content, true );
     168            if ( json_last_error() !== JSON_ERROR_NONE ) {
     169                return array(
     170                    'status'  => 'error',
     171                    'message' => __( 'Error decoding JSON', 'connect-ecommerce' ) . ': ' . json_last_error_msg(),
     172                );
     173            }
    160174            if ( ! is_array( $content ) ) {
    161175                $content = array();
    162176            }
    163             $message = __( 'Spent tokens: ', 'connect-ecommerce' ) . ( isset( $response['usage']['total_tokens'] ) ? $response['usage']['total_tokens'] : 0 );
     177            $message = __( 'Spent tokens: ', 'connect-ecommerce' ) . ( isset( $body['usage']['total_tokens'] ) ? $body['usage']['total_tokens'] : 0 );
    164178        }
    165179
  • connect-ecommerce/tags/3.1.0/includes/Helpers/HELPER.php

    r3281293 r3301423  
    116116     * @param array  $source_data Source data.
    117117     * @param array  $result Result of action.
    118      * @param string $option_prefix Prefix of option.
    119118     *
    120119     * @return void
    121120     */
    122     public static function save_log( $action, $source_data, $result, $option_prefix ) {
     121    public static function save_log( $action, $source_data, $result ) {
    123122        $logger      = wc_get_logger();
    124123        $source_data = is_array( $source_data ) ? $source_data : array( $source_data );
     
    126125        $message     = $action . ': ' . wp_json_encode( $source_data );
    127126        $message_res = 'result: ' . wp_json_encode( $result );
    128         $logger->debug( $message, array( 'source' => $option_prefix ) );
    129         $logger->debug( $message_res, array( 'source' => $option_prefix ) );
     127        $logger->debug( $message, array( 'source' => 'connect_ecommerce' ) );
     128        $logger->debug( $message_res, array( 'source' => 'connect_ecommerce' ) );
    130129    }
    131130
     
    170169        }
    171170    }
     171
     172    /**
     173     * Time to text
     174     *
     175     * @param float $time_start Start time.
     176     * @return string
     177     */
     178    public static function time_total_text( $time_start ) {
     179        $time_end = microtime(true);
     180
     181        $execution_time = round($time_end - $time_start, 2);
     182        $end = "seg";
     183
     184        if ( $execution_time > 3600 ) {
     185            $execution_time = round($execution_time / 3600, 2);
     186            $end = "horas";
     187        } elseif ( $execution_time > 60 ) {
     188            $execution_time = round($execution_time / 60, 2);
     189            $end = "min";
     190        }
     191        return $execution_time . ' ' . $end;
     192    }
    172193}
  • connect-ecommerce/tags/3.1.0/includes/Helpers/ORDER.php

    r3289663 r3301423  
    9797        }
    9898        if ( $is_debug_log ) {
    99             HELPER::save_log( 'create_order', $order_data, $result, $option_prefix );
     99            HELPER::save_log( 'create_order', $order_data, $result );
    100100        }
    101101        return $result;
  • connect-ecommerce/tags/3.1.0/includes/Helpers/PROD.php

    r3281293 r3301423  
    2929     * @param object $api_erp API Object.
    3030     * @param bool   $generate_ai Force AI.
     31     * @param int    $post_id Post ID when it comes forced.
    3132     * @return array
    3233     */
    33     public static function sync_product_item( $settings, $item, $api_erp, $generate_ai = false ) {
    34         $post_id        = 0;
     34    public static function sync_product_item( $settings, $item, $api_erp, $generate_ai = false, $post_id = 0 ) {
    3535        $status         = 'ok';
    3636        $message        = '';
    3737        $is_filtered    = self::filter_product( $settings, $item );
    3838        $item_kind      = ! empty( $item['kind'] ) ? $item['kind'] : 'simple';
    39         $is_new_product = self::find_product( $item['sku'] ) ? true : false;
     39        $is_new_product = $post_id ? false : true;
     40
     41        if ( empty( $post_id ) ) {
     42            $is_new_product = self::find_product( $item['sku'] ) ? true : false;
     43        }
    4044
    4145        if ( in_array( 'woo-product-bundle/wpc-product-bundles.php', apply_filters( 'active_plugins', get_option( 'active_plugins' ) ) ) ) {
     
    5054
    5155        if ( ! $is_filtered && $item['sku'] && 'simple' === $item_kind ) {
    52             $result_post = self::sync_product_simple( $settings, $item, $api_erp );
     56            $result_post = self::sync_product_simple( $settings, $item, $api_erp, $post_id );
    5357            $post_id     = $result_post['post_id'] ?? 0;
    5458            $message    .= $result_post['message'] ?? '';
     
    5660            // Variable product.
    5761            // Check if any variants exists.
    58             $post_parent = 0;
    59             // Activar para buscar un archivo.
    60             $any_variant_sku = false;
    61 
    62             foreach ( $item['variants'] as $variant ) {
    63                 if ( ! $variant['sku'] ) {
    64                     break;
    65                 } else {
    66                     $any_variant_sku = true;
    67                 }
    68                 $post_parent = self::find_parent_product( $variant['sku'] );
    69                 if ( $post_parent ) {
    70                     // Do not iterate if it's find it.
    71                     break;
    72                 }
    73             }
     62            $any_variant_sku = true;
     63            if ( ! $post_id ) {
     64                $post_id = 0;
     65                // Activar para buscar un archivo.
     66                $any_variant_sku = false;
     67   
     68                foreach ( $item['variants'] as $variant ) {
     69                    if ( ! $variant['sku'] ) {
     70                        break;
     71                    } else {
     72                        $any_variant_sku = true;
     73                    }
     74                    $post_id = self::find_parent_product( $variant['sku'] );
     75                    if ( $post_id ) {
     76                        // Do not iterate if it's find it.
     77                        break;
     78                    }
     79                }
     80            }
     81
     82            // Fix Parent product without SKU.
     83            if ( $post_id ) {
     84                $parent_product = wc_get_product( $post_id );
     85                if ( $parent_product && ! $parent_product->get_sku() && ! empty( $item['sku'] ) ) {
     86                    try {
     87                        $parent_product->set_sku( $item['sku'] );
     88                        $parent_product->save();
     89                    } catch ( \Exception $e ) {}
     90                }
     91                unset( $parent_product );
     92            }
     93
    7494            if ( false === $any_variant_sku ) {
    7595                $message .= __( 'Product not imported becouse any variant has got SKU: ', 'connect-ecommerce' ) . $item['name'] . '(' . $item_kind . ') <br/>';
    7696            } else {
    7797                // Update meta for product.
    78                 $result_prod = self::sync_product( $settings, $item, $api_erp, $post_parent, 'variable', null );
     98                $result_prod = self::sync_product( $settings, $item, $api_erp, $post_id, 'variable', null );
    7999                $post_id     = $result_prod['prod_id'] ?? 0;
    80                 $message    .= 0 === $post_parent || false === $post_parent ? $msg_product_created : $msg_product_synced;
     100                $message    .= 0 === $post_id || false === $post_id ? $msg_product_created : $msg_product_synced;
    81101                $message    .= $item['name'] . '. SKU: ' . $item['sku'] . '(' . $item_kind . ') ' . $result_prod['message'] ?? '';
    82102            }
    83103        } elseif ( ! $is_filtered && 'pack' === $item_kind && $plugin_pack_active ) {
    84             $post_id = self::find_product( $item['sku'] );
     104            $post_id = ! empty( $post_id ) ? $post_id : self::find_product( $item['sku'] );
    85105
    86106            if ( ! $post_id ) {
     
    144164                $result_ai = AI::generate_description( $settings_ai, $item );
    145165                if ( ! empty( $result_ai ) && 'ok' === $result_ai['status'] ) {
     166                    $message      = '';
    146167                    $product_info = array(
    147168                        'ID' => $post_id,
     
    149170                    if ( ! empty( $result_ai['data']['title'] ) ) {
    150171                        $product_info['post_title'] = $result_ai['data']['title'];
     172                    } else {
     173                        $message .=  __( 'Title not generated. ', 'connect-ecommerce' );
    151174                    }
    152175                    if ( ! empty( $result_ai['data']['body'] ) ) {
    153176                        $product_info['post_content'] = $result_ai['data']['body'];
     177                    } else {
     178                        $message .=  __( 'Post content not generated. ', 'connect-ecommerce' );
    154179                    }
    155180                    if ( ! empty( $result_ai['data']['seo_description'] ) ) {
    156181                        $product_info['post_excerpt'] = $result_ai['data']['seo_description'];
     182                    } else {
     183                        $message .=  __( 'Post excerpt not generated. ', 'connect-ecommerce' );
    157184                    }
     185
    158186                    // Update product.
    159187                    wp_update_post(
     
    168196                } else {
    169197                    $message .= '<span class="error">' . __( 'Error AI: ', 'connect-ecommerce' );
    170                     $message .= $result_ai['error'] ?? '';
     198                    $message .= $result_ai['message'] ?? '';
    171199                    $message .= '</span>';
    172200                }
     
    211239
    212240        // Start.
    213         if ( 'simple' === $type ) {
    214             $product = new \WC_Product( $product_id );
    215         } elseif ( 'variable' === $type ) {
    216             $product = new \WC_Product_Variable( $product_id );
    217         } elseif ( 'pack' === $type ) {
    218             $product = new \WC_Product( $product_id );
    219         }
     241        try {
     242            if ( 'simple' === $type ) {
     243                $product = new \WC_Product( $product_id );
     244            } elseif ( 'variable' === $type ) {
     245                $product = new \WC_Product_Variable( $product_id );
     246            } elseif ( 'pack' === $type ) {
     247                $product = new \WC_Product( $product_id );
     248            }
     249        } catch ( \Exception $e ) {
     250            return array(
     251                'status'  => 'error',
     252                'props'   => [],
     253                'message' => __( 'Error creating variable product: ', 'connect-ecommerce' ) . $e->getMessage(),
     254            );
     255        }
     256
    220257        // Common and default properties.
    221258        $product_props     = array(
    222259            'stock_status'     => 'instock',
    223260            'backorders'       => $allow_backorders,
    224             'regular_price'    => isset( $item['price'] ) ? $item['price'] : null,
     261            'regular_price'    => self::get_rate_price( $item, $rate_id ),
    225262            'length'           => isset( $item['lenght'] ) ? $item['lenght'] : '',
    226263            'width'            => isset( $item['width'] ) ? $item['width'] : '',
    227264            'height'           => isset( $item['height'] ) ? $item['height'] : '',
    228265        );
     266        $price_sale = self::get_sale_price( $item, $settings );
     267        if ( ! empty( $price_sale ) ) {
     268            $product_props['sale_price'] = $price_sale;
     269        }
    229270        $product_props_new = array();
    230271        if ( $is_new_product ) {
     
    260301        }
    261302
    262         if ( isset( $item['barcode'] ) ) {
    263             $product->set_global_unique_id( $item['barcode'] );
     303        if ( ! empty( $item['barcode'] ) ) {
     304            try {
     305                $product->set_global_unique_id( $item['barcode'] );
     306            } catch ( \Exception $e ) {
     307                // Error.
     308            }
    264309        }
    265310
     
    314359        }
    315360
    316         // Set categories.
     361        // Set attributes.
    317362        $attributes = ! empty( $item['attributes'] ) && is_array( $item['attributes'] ) ? $item['attributes'] : array();
    318363        $item_type  = array_search( $attribute_cat_id, array_column( $attributes, 'id', 'value' ) );
     
    325370
    326371        // Imports image.
    327         self::put_product_image( $settings, $item['id'], $product_id, $api_erp );
     372        self::put_product_images( $settings, $item, $product_id, $api_erp );
    328373
    329374        // Adds custom fields.
     
    389434     * @param object  $api_erp API Object.
    390435     * @param boolean $from_pack Item is a pack.
     436     * @param integer $post_id Post ID.
    391437     *
    392438     * @return array
    393439     */
    394     private static function sync_product_simple( $settings, $item, $api_erp, $from_pack = false ) {
     440    private static function sync_product_simple( $settings, $item, $api_erp, $from_pack = false, $post_id = 0 ) {
    395441        $message = '';
    396         $post_id = self::find_product( $item['sku'] );
     442        $post_id = empty( $post_id ) ? $post_id : self::find_product( $item['sku'] );
    397443        if ( ! $post_id ) {
    398444            $post_id = self::create_product_post( $settings, $item );
     
    404450            $result_prod = self::sync_product( $settings, $item, $api_erp, $post_id, 'simple', null );
    405451            $post_id     = $result_prod['prod_id'] ?? 0;
     452
     453            // Add custom taxonomies.
     454            self::add_custom_taxonomies( $post_id, $item );
    406455        }
    407456        if ( $from_pack ) {
     
    456505            }
    457506        }
     507
     508        // Add custom taxonomies.
     509        self::add_custom_taxonomies( $product_id, $item );
    458510
    459511        // Remove variations without SKU blank.
     
    491543            }
    492544            // Make Variations.
    493             if ( 'default' === $rate_id || '' === $rate_id ) {
    494                 if ( isset( $variant['price'] ) && $variant['price'] ) {
    495                     $variation_price = $variant['price'];
    496                 } else {
    497                     $variation_price = 0;
    498                 }
    499             } else {
    500                 $variant_price_key = array_search( $rate_id, array_column( $variant['rates'], 'id' ) );
    501                 $variation_price   = $variant['rates'][ $variant_price_key ]['subtotal'];
    502             }
     545            $variation_price   = self::get_rate_price( $variant, $rate_id );
    503546            $variation_props = array(
    504547                'parent_id'     => $product_id,
     
    506549                'regular_price' => $variation_price,
    507550            );
     551
     552            $price_sale = self::get_sale_price( $variant, $settings );
     553            if ( ! empty( $price_sale ) ) {
     554                $variation_props['sale_price'] = $price_sale;
     555            }
    508556            if ( 0 === $variation_id ) {
    509557                // New variation.
     
    522570            }
    523571            $variation = new \WC_Product_Variation( $variation_id );
     572            if ( ! empty( $variant['barcode'] ) ) {
     573                try {
     574                    $variation->set_global_unique_id( $item['barcode'] );
     575                } catch ( \Exception $e ) {
     576                    // Error.
     577                }
     578            }
    524579            $variation->set_props( $variation_props );
    525580            // Stock.
     
    721776     * @return string $product_id Products id.
    722777     */
    723     public static function find_product( $sku ) {
     778    public static function find_product( $sku, $post_type = 'product' ) {
    724779        global $wpdb;
    725         $post_type    = 'product';
    726780        $meta_key     = '_sku';
    727781        $result_query = $wpdb->get_var( $wpdb->prepare( "SELECT P.ID FROM $wpdb->posts AS P LEFT JOIN $wpdb->postmeta AS PM ON PM.post_id = P.ID WHERE P.post_type = '$post_type' AND PM.meta_key='$meta_key' AND PM.meta_value=%s AND P.post_status != 'trash' LIMIT 1", $sku ) );
     
    737791     */
    738792    public static function find_parent_product( $sku ) {
    739         global $wpdb;
    740         $post_id_var = $wpdb->get_var( $wpdb->prepare( "SELECT post_id FROM $wpdb->postmeta WHERE meta_key='_sku' AND meta_value=%s LIMIT 1", $sku ) );
     793        $post_id_var = self::find_product( $sku, 'product_variation' );
    741794
    742795        if ( $post_id_var ) {
    743             $post_parent = wp_get_post_parent_id( $post_id_var );
     796            $post_parent = wp_get_post_parent_id( (int) $post_id_var );
    744797            return $post_parent;
    745798        }
     
    808861     * Gets image from API products
    809862     *
    810      * @param string $item_id Id of API to get information.
     863     * @param string $item Item of API to get information.
    811864     * @param string $product_id Id of product to get information.
    812865     * @param object $api_erp API Object.
    813866     *
    814      * @return array Array of products imported via API.
    815      */
    816     public static function put_product_image( $settings, $item_id, $product_id, $api_erp ) {
    817         // Don't import if there is thumbnail.
    818         if ( has_post_thumbnail( $product_id ) ) {
     867     * @return void
     868     */
     869    public static function put_product_images( $settings, $item, $product_id, $api_erp ) {
     870        if ( self::has_valid_thumbnail( $product_id ) ) {
    819871            return false;
    820872        }
    821873
    822         $result_api = $api_erp->get_image_product( $settings, $item_id, $product_id );
    823 
    824         if ( isset( $result_api['upload']['url'] ) ) {
    825             $attachment = array(
    826                 'guid'           => $result_api['upload']['url'],
    827                 'post_mime_type' => $result_api['content_type'],
    828                 'post_title'     => get_the_title( $product_id ),
    829                 'post_content'   => '',
    830                 'post_status'    => 'inherit',
    831             );
    832             $attach_id  = wp_insert_attachment( $attachment, $result_api['upload']['file'], 0 );
    833             add_post_meta( $product_id, '_thumbnail_id', $attach_id, true );
     874        $images = array();
     875        if ( ! empty( $item['images'] ) ) {
     876            $images = $item['images'] ?? array();
     877        } else {
     878            // Ask API for image.
     879            $result_api = $api_erp->get_image_product( $settings, $item['id'], $product_id );
    834880
    835881            if ( isset( $body_response['errors'] ) ) {
     
    838884                return false;
    839885            }
    840 
    841             return $attach_id;
     886            if ( isset( $result_api['upload']['url'] ) ){
     887                $images[] = [
     888                    'url'          => $result_api['upload']['url'],
     889                    'file'         => $result_api['upload']['file'],
     890                    'content_type' => $result_api['content_type'],
     891                ];
     892            }
     893        }
     894
     895        if ( empty( $images ) ) {
     896            return;
     897        }
     898
     899        $first_image = true;
     900        foreach ( $images as $image ) {
     901            $attachment = array(
     902                'guid'           => $image['url'] ?? '',
     903                'post_mime_type' => $image['content_type'] ?? '',
     904                'post_title'     => $image['title'] ?? get_the_title( $product_id ),
     905                'post_content'   => $image['content'] ?? '',
     906                'post_status'    => 'inherit',
     907            );
     908
     909            if ( empty( $image['file'] ) ) {
     910                // Download image to server
     911                $image_url = $image['url'] ?? '';
     912                if ( empty( $image_url ) ) {
     913                    continue;
     914                }
     915
     916                $file_array = [];
     917                $file_array['name'] = basename( $image_url );
     918                $file_array['tmp_name'] = download_url( $image_url );
     919
     920                // Check for download errors
     921                if ( is_wp_error( $file_array['tmp_name'] ) ) {
     922                    continue;
     923                }
     924
     925                $attach_id = media_handle_sideload( $file_array, $product_id, $attachment['post_title'], $attachment );
     926
     927                // Check for attachment errors
     928                if (is_wp_error($attach_id)) {
     929                    @unlink($file_array['tmp_name']);
     930                    continue;
     931                }
     932            } else {
     933                if ( ! file_exists( $image['file'] ) ) {
     934                    continue;
     935                }
     936
     937                $attach_id  = wp_insert_attachment( $attachment, $image['file'], 0 );
     938            }
     939
     940            if ( $first_image ) {
     941                $first_image = false;
     942                // Set the product image.
     943                add_post_meta( $product_id, '_thumbnail_id', $attach_id, true );
     944            } else {
     945                // Add the image to the product gallery.
     946                $gallery = get_post_meta( $product_id, '_product_image_gallery', true );
     947                $gallery = $gallery ? $gallery . ',' . $attach_id : $attach_id;
     948                update_post_meta( $product_id, '_product_image_gallery', $gallery );
     949            }
    842950        }
    843951    }
     
    9561064        }
    9571065    }
     1066
     1067    /**
     1068     * Get sale price from item
     1069     *
     1070     * @param array $item Item from API.
     1071     * @param array $settings Settings of the plugin.
     1072     *
     1073     * @return string
     1074     */
     1075    private static function get_sale_price( $item, $settings ) {
     1076        $pricesale_discount = (float) $settings['pricesale_discount'] ?? 0;
     1077        if ( empty( $pricesale_discount ) || empty( $item['price'] ) ) {
     1078            return '';
     1079        }
     1080        $price_sale = $item['price'] - ( $item['price'] * ( $pricesale_discount / 100 ) );
     1081        if ( $price_sale > 0 ) {
     1082            return number_format( $price_sale, 2, '.', '' );
     1083        } else {
     1084            return '';
     1085        }
     1086    }
     1087
     1088    /**
     1089     * Get attribute category ID
     1090     *
     1091     * @param array $item Item from API.
     1092     *
     1093     * @return int
     1094     */
     1095    private static function get_rate_price( $item, $rate_id ) {
     1096        if ( empty( $item ) ) {
     1097            return null;
     1098        }
     1099        if ( 'default' === $rate_id || '' === $rate_id || empty( $item['rates'] ) || ! is_array( $item['rates'] ) ) {
     1100            return isset( $item['price'] ) ? $item['price'] : null;
     1101        } else {
     1102            $price_key = array_search( $rate_id, array_column( $item['rates'], 'id' ) );
     1103            return isset( $item['rates'][ $price_key ]['subtotal'] ) ? $item['rates'][ $price_key ]['subtotal'] : null;
     1104        }
     1105    }
     1106
     1107    /**
     1108     * Add custom taxonomies to product
     1109     *
     1110     * @param int   $product_id Product ID.
     1111     * @param array $item Item from API.
     1112     *
     1113     * @return void
     1114     */
     1115    private static function add_custom_taxonomies( $product_id, $item ) {
     1116        // Set taxonomies.
     1117        if ( ! empty( $item['taxonomies'] ) && is_array( $item['taxonomies'] ) ) {
     1118            foreach ( $item['taxonomies'] as $taxonomy ) {
     1119                if ( empty( $taxonomy['id'] ) || empty( $taxonomy['value'] ) ) {
     1120                    continue;
     1121                }
     1122                TAX::assign_product_term( $product_id, $taxonomy['id'], $taxonomy['value'], true );
     1123            }
     1124        }
     1125    }
     1126
     1127    /**
     1128     * Checks if product has a valid thumbnail.
     1129     *
     1130     * @param int $product_id Product ID.
     1131     * @return bool
     1132     */
     1133    private static function has_valid_thumbnail( $product_id ) {
     1134        $thumbnail_id = get_post_thumbnail_id( $product_id );
     1135        if ( ! $thumbnail_id ) {
     1136            return false;
     1137        }
     1138        $image_path = get_attached_file( $thumbnail_id );
     1139        if ( ! $image_path || ! file_exists( $image_path ) ) {
     1140            return false;
     1141        }
     1142        $image_url = wp_get_attachment_url( $thumbnail_id );
     1143        if ( ! $image_url ) {
     1144            return false;
     1145        }
     1146        return true;
     1147    }
    9581148}
  • connect-ecommerce/tags/3.1.0/includes/Helpers/TAX.php

    r3281293 r3301423  
    218218     * @param string $post_id Post id of actual post id.
    219219     * @param array  $taxonomy_slug Slug of taxonomy.
    220      * @param array  $category_array Array of category.
     220     * @param array|string  $terms Array of terms.
    221221     * @return void
    222222     */
    223     private static function assign_product_term( $post_id, $taxonomy_slug, $category_array ) {
     223    public static function assign_product_term( $post_id, $taxonomy_slug, $terms ) {
    224224        $parent_term      = '';
    225         $term_levels      = count( $category_array );
     225        $terms                      = is_array( $terms ) ? $terms : array( $terms );
     226        $term_levels      = count( $terms );
    226227        $term_level_index = 1;
    227228
    228         foreach ( $category_array as $category_name ) {
    229             $category_name = self::sanitize_text( $category_name );
    230             $search_term   = term_exists( $category_name, $taxonomy_slug );
     229        foreach ( $terms as $term ) {
     230            $term        = self::sanitize_text( $term );
     231            $search_term = term_exists( $term, $taxonomy_slug );
    231232
    232233            if ( 0 === $search_term || null === $search_term ) {
    233234                // Creates taxonomy.
    234235                $args_term = array(
    235                     'slug' => sanitize_title( $category_name ),
     236                    'slug' => sanitize_title( $term ),
    236237                );
    237238                if ( $parent_term ) {
     
    239240                }
    240241                $search_term = wp_insert_term(
    241                     $category_name,
     242                    $term,
    242243                    $taxonomy_slug,
    243244                    $args_term
    244245                );
    245246            }
    246             if ( $term_level_index === $term_levels ) {
    247                 wp_set_object_terms( $post_id, (int) $search_term['term_id'], $taxonomy_slug );
     247           
     248            // Check if term was found or created successfully
     249            if ( ! is_wp_error( $search_term ) && $term_level_index === $term_levels ) {
     250                $term_id = isset( $search_term['term_id'] ) ? (int) $search_term['term_id'] : (int) $search_term;
     251                wp_set_object_terms( $post_id, $term_id, $taxonomy_slug );
    248252            }
    249253
    250254            // Next iteration for child.
    251             $parent_term = $search_term['term_id'];
     255            $parent_term = (int) $search_term['term_id'];
    252256            $term_level_index++;
    253257        }
     
    262266    private static function sanitize_text( $text ) {
    263267        $text = str_replace( '>', '&gt;', $text );
    264         return $text;
     268        return sanitize_text_field( $text );
    265269    }
    266270
  • connect-ecommerce/tags/3.1.0/includes/Plugin_Main.php

    r3281293 r3301423  
    2828
    2929    /**
     30     * Options of plugin.
     31     *
     32     * @var array
     33     */
     34    private $options = array();
     35
     36    /**
    3037     * Construct of class
    3138     *
     
    3340     */
    3441    public function __construct( $options = array() ) {
     42        $this->options = $options;
    3543        if ( is_admin() ) {
    3644            new Settings( $options );
     
    4452        new MyAccount( $options );
    4553    }
     54
     55    /**
     56     * Get options of plugin.
     57     *
     58     * @return array
     59     */
     60    public function get_options( ) {
     61        return $this->options;
     62    }
    4663}
  • connect-ecommerce/tags/3.1.0/includes/assets/sync-import.js

    r3281293 r3301423  
    4444}
    4545
    46 function syncProductERP( element, action, product_erp_id = 0, product_sku = '' ) {
     46function syncProductERP( element, action, product_erp_id = 0, product_sku = '', product_id = 0 ) {
    4747    element.classList.add('disabled');
    4848    element.innerHTML = ConEcom_ajaxAction.label_syncing + ' <span class="spinner is-active"></span>';
     
    5858            'Cache-Control': 'no-cache',
    5959        },
    60         body: 'action=' + action + '&nonce=' + ConEcom_ajaxAction.nonce + '&loop=' + loop + '&product_erp_id=' + product_erp_id + '&product_sku=' + product_sku + '&product_ai=' + productAI,
     60        body: 'action=' + action + '&nonce=' + ConEcom_ajaxAction.nonce + '&loop=' + loop + '&product_erp_id=' + product_erp_id + '&product_sku=' + product_sku + '&product_id=' + product_id + '&product_ai=' + productAI,
    6161    })
    6262    .then( (resp) => resp.json() )
     
    6565        element.innerHTML = ConEcom_ajaxAction.label_sync;
    6666
    67         // Refresh the page
    68         location.reload();
     67        console.log(results.data);
     68        // Message handling
     69        if (results.data.message !== undefined) {
     70            const aiInput = document.querySelector('#connect_ecommerce_ai');
     71            if (aiInput) {
     72                const aiLabel = aiInput.closest('label');
     73                const aiMessage = document.createElement('div');
     74                aiMessage.className = 'ai-message';
     75                aiMessage.innerHTML = results.data.message;
     76               
     77                const targetElement = aiLabel || aiInput;
     78                if (targetElement.nextSibling) {
     79                    targetElement.parentNode.insertBefore(aiMessage, targetElement.nextSibling);
     80                } else {
     81                    targetElement.parentNode.appendChild(aiMessage);
     82                }
     83            }
     84        }
     85
     86        // Reload the page after 8 seconds if the sync was successful
     87        if (results.success) {
     88            setTimeout(() => {
     89                window.location.reload();
     90            }, 8000);
     91        }
    6992    })
    7093    .catch(err => console.log(err));
  • connect-ecommerce/tags/3.1.0/readme.txt

    r3289663 r3301423  
    4747[Official Repository GitHub](https://github.com/closemarketing/connect-ecommerce)
    4848
     49You can use WP CLI to import products from the command line. The command is:
     50```
     51wp conecom products --update --ai=none,new,all
     52```
     53
    4954== External services ==
    5055
     
    5964
    6065== Changelog ==
     66
     67= 3.1.0 =
     68* Added: WP CLI command to import products.
     69* Fully support to import EAN to WooCommerce.
     70* Added: Import image products with different method.
     71* Added: Result API import in widget product.
     72* Added: Save parent SKU in product if does not exist.
     73* Added: Check if image product file exists before import.
     74* Fixed: AI connection not working in some cases.
     75* Fixed: Some errors getting products from shop to syncronize.
     76* Fixed: Not getting prices rates from API.
     77* Fixed: Prevent error when WooCommerce does not load the product.
    6178
    6279= 3.0.1 =
  • connect-ecommerce/tags/3.1.0/vendor/composer/installed.php

    r3289663 r3301423  
    22    'root' => array(
    33        'name' => 'closemarketing/connect-ecommerce',
    4         'pretty_version' => '3.0.1',
    5         'version' => '3.0.1.0',
    6         'reference' => '4b85748d444a7a4ddea31f4494598d5fffd54f4a',
     4        'pretty_version' => '3.1.0',
     5        'version' => '3.1.0.0',
     6        'reference' => 'f3639f9784b938002847fc0b6395dc83d2c1b030',
    77        'type' => 'library',
    88        'install_path' => __DIR__ . '/../../',
     
    1212    'versions' => array(
    1313        'closemarketing/connect-ecommerce' => array(
    14             'pretty_version' => '3.0.1',
    15             'version' => '3.0.1.0',
    16             'reference' => '4b85748d444a7a4ddea31f4494598d5fffd54f4a',
     14            'pretty_version' => '3.1.0',
     15            'version' => '3.1.0.0',
     16            'reference' => 'f3639f9784b938002847fc0b6395dc83d2c1b030',
    1717            'type' => 'library',
    1818            'install_path' => __DIR__ . '/../../',
  • connect-ecommerce/trunk/connect-ecommerce.php

    r3289663 r3301423  
    66 * Author: Closetechnology
    77 * Author URI: https://close.technology/
    8  * Version: 3.0.1
     8 * Version: 3.1.0
    99 *
    1010 * @package WordPress
     
    1717defined( 'ABSPATH' ) || exit;
    1818
    19 define( 'CONECOM_VERSION', '3.0.1' );
     19define( 'CONECOM_VERSION', '3.1.0' );
    2020define( 'CONECOM_FILE', __FILE__ );
    2121define( 'CONECOM_PLUGIN_URL', plugin_dir_url( __FILE__ ) );
     
    2626require_once CONECOM_PLUGIN_PATH . 'vendor/autoload.php';
    2727
    28 add_action( 'init', 'conecom_loads' );
    29 /**
    30  * Connect WooCommerce loads.
    31  *
    32  * @return void
    33  */
    34 function conecom_loads() {
    35     /**
     28function conecom_get_options() {
     29        /**
    3630     * Default values
    3731     */
    3832    global $wpdb;
    3933
    40     $conecom_options = apply_filters(
     34    return apply_filters(
    4135        'conecom_options_plugin',
    4236        [
     
    114108        ]
    115109    );
     110}
    116111
     112
     113
     114add_action( 'init', 'conecom_loads' );
     115/**
     116 * Connect WooCommerce loads.
     117 *
     118 * @return void
     119 */
     120function conecom_loads() {
    117121    require_once CONECOM_PLUGIN_PATH . 'includes/Plugin_Main.php';
    118122    require_once CONECOM_PLUGIN_PATH . 'includes/Connector/class-api-clientify.php';
    119123
     124    $conecom_options = conecom_get_options();
    120125    new CLOSE\ConnectEcommerce\Base( $conecom_options );
    121126}
     127
     128if ( defined( 'WP_CLI' ) && WP_CLI ) {
     129    require_once CONECOM_PLUGIN_PATH . 'includes/CLI/Import_Products_Command.php';
     130
     131    /**
     132     * Registers our command when cli get's initialized.
     133     *
     134     * @since  1.0.0
     135     * @author David Perez
     136     */
     137    function conecom_import_products_register_commands() {
     138        WP_CLI::add_command('conecom', 'Import_Products_Command' );
     139    }
     140
     141    add_action( 'cli_init', 'conecom_import_products_register_commands', 20 );
     142}
  • connect-ecommerce/trunk/includes/Admin/Import_Products.php

    r3281293 r3301423  
    174174        $product_erp_id = isset( $_POST['product_erp_id'] ) ? sanitize_text_field( wp_unslash( $_POST['product_erp_id'] ) ) : '';
    175175        $product_sku    = isset( $_POST['product_sku'] ) ? sanitize_text_field( wp_unslash( $_POST['product_sku'] ) ) : '';
     176        $product_id     = isset( $_POST['product_id'] ) ? (int) $_POST['product_id'] : '';
    176177        $message        = '';
    177178        $res_message    = '';
    178         $generate_ai    = isset( $_POST['product_ai'] ) ? sanitize_key( $_POST['product_ai'] ) : 'none';
     179        $generate_ai    = ! empty( $_POST['product_ai'] ) ? sanitize_key( $_POST['product_ai'] ) : 'none';
     180        $generate_ai    = 'true' === $generate_ai ? 'all' : $generate_ai;
    179181        $api_pagination = ! empty( $this->options['api_pagination'] ) ? $this->options['api_pagination'] : false;
    180182
     
    224226        $this->msg_error_products = array();
    225227
    226         $result_sync = PROD::sync_product_item( $this->settings, $item, $this->connapi_erp, $this->options['slug'], $generate_ai );
     228        $result_sync = PROD::sync_product_item( $this->settings, $item, $this->connapi_erp, $generate_ai, $product_id );
    227229        $post_id     = $result_sync['post_id'] ?? 0;
    228230        if ( 'error' === $result_sync['status'] ) {
     
    321323
    322324                $product_api = $this->connapi_erp->get_products( $product_id );
    323                 $result      = PROD::sync_product_item( $this->settings, $product_api, $this->connapi_erp, $this->options['slug'] );
     325                $result      = PROD::sync_product_item( $this->settings, $product_api, $this->connapi_erp );
    324326                if ( $is_table_sync ) {
    325327                    CRON::save_product_sync( $this->options['table_sync'], $result['prod_id'], $this->options['slug'] );
  • connect-ecommerce/trunk/includes/Admin/Settings.php

    r3289663 r3301423  
    6767     */
    6868    private $connapi_erp;
    69 
    70     /**
    71      * Settings slug
    72      *
    73      * @var string
    74      */
    75     private $settings_slug;
    7669
    7770    /**
     
    544537                );
    545538            }
     539
     540            add_settings_field(
     541                'wcpimh_make_discount',
     542                __( 'Percentage to Make a discount from prices and save in sale price?', 'connect-ecommerce' ),
     543                array( $this, 'pricesale_discount_option_callback' ),
     544                'connect_ecommerce_admin',
     545                'connect_woocommerce_setting_section'
     546            );
    546547
    547548            if ( $this->options['product_price_rate_option'] ) {
     
    920921                'catattr'        => '',
    921922                'filter'         => '',
     923                'pricesale_discount' => '',
    922924                'filter_sku'     => '',
    923925                'tax_option'     => 'no',
     
    12651267        </select>
    12661268        <?php
     1269    }
     1270
     1271    /**
     1272     * Percentage price discount
     1273     *
     1274     * @return void
     1275     */
     1276    public function pricesale_discount_option_callback() {
     1277        printf(
     1278            '<input class="regular-text" type="text" name="connect_ecommerce[' . esc_html( $this->connector ) . '][pricesale_discount]" id="wcpimh_pricesale_discount" value="%s" style="width:60px">%%',
     1279            isset( $this->settings['pricesale_discount'] ) ? esc_attr( $this->settings['pricesale_discount'] ) : ''
     1280        );
    12671281    }
    12681282
  • connect-ecommerce/trunk/includes/Admin/Widget_Product.php

    r3289663 r3301423  
    8787        echo '\'' . esc_html( $product_erp_id ) . '\',';
    8888        echo '\'' . esc_html( $product->get_sku() ) . '\',';
    89         echo 'this.id)">' . esc_html__( 'Sync', 'connect-ecommerce' ) . '</div>';
     89        echo '\'' . esc_html( $product_id ) . '\',';
     90        echo ')">' . esc_html__( 'Sync', 'connect-ecommerce' ) . '</div>';
    9091        echo '</td>';
    9192        echo '</tr>';
  • connect-ecommerce/trunk/includes/Helpers/AI.php

    r3281293 r3301423  
    9797        );
    9898        $content .= PHP_EOL . __( 'Generate a Title, Content, Title SEO and SEO description and export it in format JSON, with elements: title, body, seo_title, seo_description', 'connect-ecommerce' );
     99        $content .= PHP_EOL . __( 'Return only a valid and complete JSON object. If the content is too long, split it into multiple parts and clearly indicate when to continue. Do not include any text outside of the JSON.', 'connect-ecommerce' );
    99100
    100101        $token = isset( $settings['token'] ) ? $settings['token'] : '';
     
    123124                'Authorization' => 'Bearer ' . $token,
    124125            ),
     126            'timeout' => 90,
    125127            'body'    => wp_json_encode(
    126128                array(
     
    136138                    'n'                 => 1,
    137139                    'stream'            => false,
    138                     'max_tokens'        => 250,
     140                    'max_tokens'        => 1024,
    139141                    'presence_penalty'  => 0,
    140142                    'frequency_penalty' => 0,
     
    145147        $response      = wp_remote_post( $api_url, $args );
    146148        $response_code = wp_remote_retrieve_response_code( $response );
    147         $response      = json_decode( wp_remote_retrieve_body( $response ), true );
     149        $body          = json_decode( wp_remote_retrieve_body( $response ), true );
    148150
    149151        if ( 200 !== $response_code ) {
     152            $message .= sanitize_text_field( $response['error']['message'] ) ?? '';
     153            $message .= sanitize_text_field( $response['errors']['http_request_failed'] ) ?? '';
     154            $message .= $message ?? __( 'Unknown error', 'connect-ecommerce' );
     155
    150156            return array(
    151                 'status'  => 0,
    152                 'message' => isset( $response['error']['message'] ) ? sanitize_text_field( $response['error']['message'] ) : __( 'Unknown error', 'connect-ecommerce' ),
     157                'status'  => 'error',
     158                'message' => $message,
    153159            );
    154160        }
    155161        $content = array();
    156         if ( isset( $response['choices'][0]['message']['content'] ) ) {
    157             $content = str_replace( '```json', '', $response['choices'][0]['message']['content'] );
    158             $content = str_replace( '```', '', $content );
     162        if ( isset( $body['choices'][0]['message']['content'] ) ) {
     163            error_log( '$content: ' . print_r( $body['choices'][0]['message']['content'], true ) );
     164            $content = str_replace( '```json', '', $body['choices'][0]['message']['content'] );
     165            $content = preg_replace( '/```[\w]*\s*/', '', $content );
     166            $content = trim( $content );
    159167            $content = json_decode( $content, true );
     168            if ( json_last_error() !== JSON_ERROR_NONE ) {
     169                return array(
     170                    'status'  => 'error',
     171                    'message' => __( 'Error decoding JSON', 'connect-ecommerce' ) . ': ' . json_last_error_msg(),
     172                );
     173            }
    160174            if ( ! is_array( $content ) ) {
    161175                $content = array();
    162176            }
    163             $message = __( 'Spent tokens: ', 'connect-ecommerce' ) . ( isset( $response['usage']['total_tokens'] ) ? $response['usage']['total_tokens'] : 0 );
     177            $message = __( 'Spent tokens: ', 'connect-ecommerce' ) . ( isset( $body['usage']['total_tokens'] ) ? $body['usage']['total_tokens'] : 0 );
    164178        }
    165179
  • connect-ecommerce/trunk/includes/Helpers/HELPER.php

    r3281293 r3301423  
    116116     * @param array  $source_data Source data.
    117117     * @param array  $result Result of action.
    118      * @param string $option_prefix Prefix of option.
    119118     *
    120119     * @return void
    121120     */
    122     public static function save_log( $action, $source_data, $result, $option_prefix ) {
     121    public static function save_log( $action, $source_data, $result ) {
    123122        $logger      = wc_get_logger();
    124123        $source_data = is_array( $source_data ) ? $source_data : array( $source_data );
     
    126125        $message     = $action . ': ' . wp_json_encode( $source_data );
    127126        $message_res = 'result: ' . wp_json_encode( $result );
    128         $logger->debug( $message, array( 'source' => $option_prefix ) );
    129         $logger->debug( $message_res, array( 'source' => $option_prefix ) );
     127        $logger->debug( $message, array( 'source' => 'connect_ecommerce' ) );
     128        $logger->debug( $message_res, array( 'source' => 'connect_ecommerce' ) );
    130129    }
    131130
     
    170169        }
    171170    }
     171
     172    /**
     173     * Time to text
     174     *
     175     * @param float $time_start Start time.
     176     * @return string
     177     */
     178    public static function time_total_text( $time_start ) {
     179        $time_end = microtime(true);
     180
     181        $execution_time = round($time_end - $time_start, 2);
     182        $end = "seg";
     183
     184        if ( $execution_time > 3600 ) {
     185            $execution_time = round($execution_time / 3600, 2);
     186            $end = "horas";
     187        } elseif ( $execution_time > 60 ) {
     188            $execution_time = round($execution_time / 60, 2);
     189            $end = "min";
     190        }
     191        return $execution_time . ' ' . $end;
     192    }
    172193}
  • connect-ecommerce/trunk/includes/Helpers/ORDER.php

    r3289663 r3301423  
    9797        }
    9898        if ( $is_debug_log ) {
    99             HELPER::save_log( 'create_order', $order_data, $result, $option_prefix );
     99            HELPER::save_log( 'create_order', $order_data, $result );
    100100        }
    101101        return $result;
  • connect-ecommerce/trunk/includes/Helpers/PROD.php

    r3281293 r3301423  
    2929     * @param object $api_erp API Object.
    3030     * @param bool   $generate_ai Force AI.
     31     * @param int    $post_id Post ID when it comes forced.
    3132     * @return array
    3233     */
    33     public static function sync_product_item( $settings, $item, $api_erp, $generate_ai = false ) {
    34         $post_id        = 0;
     34    public static function sync_product_item( $settings, $item, $api_erp, $generate_ai = false, $post_id = 0 ) {
    3535        $status         = 'ok';
    3636        $message        = '';
    3737        $is_filtered    = self::filter_product( $settings, $item );
    3838        $item_kind      = ! empty( $item['kind'] ) ? $item['kind'] : 'simple';
    39         $is_new_product = self::find_product( $item['sku'] ) ? true : false;
     39        $is_new_product = $post_id ? false : true;
     40
     41        if ( empty( $post_id ) ) {
     42            $is_new_product = self::find_product( $item['sku'] ) ? true : false;
     43        }
    4044
    4145        if ( in_array( 'woo-product-bundle/wpc-product-bundles.php', apply_filters( 'active_plugins', get_option( 'active_plugins' ) ) ) ) {
     
    5054
    5155        if ( ! $is_filtered && $item['sku'] && 'simple' === $item_kind ) {
    52             $result_post = self::sync_product_simple( $settings, $item, $api_erp );
     56            $result_post = self::sync_product_simple( $settings, $item, $api_erp, $post_id );
    5357            $post_id     = $result_post['post_id'] ?? 0;
    5458            $message    .= $result_post['message'] ?? '';
     
    5660            // Variable product.
    5761            // Check if any variants exists.
    58             $post_parent = 0;
    59             // Activar para buscar un archivo.
    60             $any_variant_sku = false;
    61 
    62             foreach ( $item['variants'] as $variant ) {
    63                 if ( ! $variant['sku'] ) {
    64                     break;
    65                 } else {
    66                     $any_variant_sku = true;
    67                 }
    68                 $post_parent = self::find_parent_product( $variant['sku'] );
    69                 if ( $post_parent ) {
    70                     // Do not iterate if it's find it.
    71                     break;
    72                 }
    73             }
     62            $any_variant_sku = true;
     63            if ( ! $post_id ) {
     64                $post_id = 0;
     65                // Activar para buscar un archivo.
     66                $any_variant_sku = false;
     67   
     68                foreach ( $item['variants'] as $variant ) {
     69                    if ( ! $variant['sku'] ) {
     70                        break;
     71                    } else {
     72                        $any_variant_sku = true;
     73                    }
     74                    $post_id = self::find_parent_product( $variant['sku'] );
     75                    if ( $post_id ) {
     76                        // Do not iterate if it's find it.
     77                        break;
     78                    }
     79                }
     80            }
     81
     82            // Fix Parent product without SKU.
     83            if ( $post_id ) {
     84                $parent_product = wc_get_product( $post_id );
     85                if ( $parent_product && ! $parent_product->get_sku() && ! empty( $item['sku'] ) ) {
     86                    try {
     87                        $parent_product->set_sku( $item['sku'] );
     88                        $parent_product->save();
     89                    } catch ( \Exception $e ) {}
     90                }
     91                unset( $parent_product );
     92            }
     93
    7494            if ( false === $any_variant_sku ) {
    7595                $message .= __( 'Product not imported becouse any variant has got SKU: ', 'connect-ecommerce' ) . $item['name'] . '(' . $item_kind . ') <br/>';
    7696            } else {
    7797                // Update meta for product.
    78                 $result_prod = self::sync_product( $settings, $item, $api_erp, $post_parent, 'variable', null );
     98                $result_prod = self::sync_product( $settings, $item, $api_erp, $post_id, 'variable', null );
    7999                $post_id     = $result_prod['prod_id'] ?? 0;
    80                 $message    .= 0 === $post_parent || false === $post_parent ? $msg_product_created : $msg_product_synced;
     100                $message    .= 0 === $post_id || false === $post_id ? $msg_product_created : $msg_product_synced;
    81101                $message    .= $item['name'] . '. SKU: ' . $item['sku'] . '(' . $item_kind . ') ' . $result_prod['message'] ?? '';
    82102            }
    83103        } elseif ( ! $is_filtered && 'pack' === $item_kind && $plugin_pack_active ) {
    84             $post_id = self::find_product( $item['sku'] );
     104            $post_id = ! empty( $post_id ) ? $post_id : self::find_product( $item['sku'] );
    85105
    86106            if ( ! $post_id ) {
     
    144164                $result_ai = AI::generate_description( $settings_ai, $item );
    145165                if ( ! empty( $result_ai ) && 'ok' === $result_ai['status'] ) {
     166                    $message      = '';
    146167                    $product_info = array(
    147168                        'ID' => $post_id,
     
    149170                    if ( ! empty( $result_ai['data']['title'] ) ) {
    150171                        $product_info['post_title'] = $result_ai['data']['title'];
     172                    } else {
     173                        $message .=  __( 'Title not generated. ', 'connect-ecommerce' );
    151174                    }
    152175                    if ( ! empty( $result_ai['data']['body'] ) ) {
    153176                        $product_info['post_content'] = $result_ai['data']['body'];
     177                    } else {
     178                        $message .=  __( 'Post content not generated. ', 'connect-ecommerce' );
    154179                    }
    155180                    if ( ! empty( $result_ai['data']['seo_description'] ) ) {
    156181                        $product_info['post_excerpt'] = $result_ai['data']['seo_description'];
     182                    } else {
     183                        $message .=  __( 'Post excerpt not generated. ', 'connect-ecommerce' );
    157184                    }
     185
    158186                    // Update product.
    159187                    wp_update_post(
     
    168196                } else {
    169197                    $message .= '<span class="error">' . __( 'Error AI: ', 'connect-ecommerce' );
    170                     $message .= $result_ai['error'] ?? '';
     198                    $message .= $result_ai['message'] ?? '';
    171199                    $message .= '</span>';
    172200                }
     
    211239
    212240        // Start.
    213         if ( 'simple' === $type ) {
    214             $product = new \WC_Product( $product_id );
    215         } elseif ( 'variable' === $type ) {
    216             $product = new \WC_Product_Variable( $product_id );
    217         } elseif ( 'pack' === $type ) {
    218             $product = new \WC_Product( $product_id );
    219         }
     241        try {
     242            if ( 'simple' === $type ) {
     243                $product = new \WC_Product( $product_id );
     244            } elseif ( 'variable' === $type ) {
     245                $product = new \WC_Product_Variable( $product_id );
     246            } elseif ( 'pack' === $type ) {
     247                $product = new \WC_Product( $product_id );
     248            }
     249        } catch ( \Exception $e ) {
     250            return array(
     251                'status'  => 'error',
     252                'props'   => [],
     253                'message' => __( 'Error creating variable product: ', 'connect-ecommerce' ) . $e->getMessage(),
     254            );
     255        }
     256
    220257        // Common and default properties.
    221258        $product_props     = array(
    222259            'stock_status'     => 'instock',
    223260            'backorders'       => $allow_backorders,
    224             'regular_price'    => isset( $item['price'] ) ? $item['price'] : null,
     261            'regular_price'    => self::get_rate_price( $item, $rate_id ),
    225262            'length'           => isset( $item['lenght'] ) ? $item['lenght'] : '',
    226263            'width'            => isset( $item['width'] ) ? $item['width'] : '',
    227264            'height'           => isset( $item['height'] ) ? $item['height'] : '',
    228265        );
     266        $price_sale = self::get_sale_price( $item, $settings );
     267        if ( ! empty( $price_sale ) ) {
     268            $product_props['sale_price'] = $price_sale;
     269        }
    229270        $product_props_new = array();
    230271        if ( $is_new_product ) {
     
    260301        }
    261302
    262         if ( isset( $item['barcode'] ) ) {
    263             $product->set_global_unique_id( $item['barcode'] );
     303        if ( ! empty( $item['barcode'] ) ) {
     304            try {
     305                $product->set_global_unique_id( $item['barcode'] );
     306            } catch ( \Exception $e ) {
     307                // Error.
     308            }
    264309        }
    265310
     
    314359        }
    315360
    316         // Set categories.
     361        // Set attributes.
    317362        $attributes = ! empty( $item['attributes'] ) && is_array( $item['attributes'] ) ? $item['attributes'] : array();
    318363        $item_type  = array_search( $attribute_cat_id, array_column( $attributes, 'id', 'value' ) );
     
    325370
    326371        // Imports image.
    327         self::put_product_image( $settings, $item['id'], $product_id, $api_erp );
     372        self::put_product_images( $settings, $item, $product_id, $api_erp );
    328373
    329374        // Adds custom fields.
     
    389434     * @param object  $api_erp API Object.
    390435     * @param boolean $from_pack Item is a pack.
     436     * @param integer $post_id Post ID.
    391437     *
    392438     * @return array
    393439     */
    394     private static function sync_product_simple( $settings, $item, $api_erp, $from_pack = false ) {
     440    private static function sync_product_simple( $settings, $item, $api_erp, $from_pack = false, $post_id = 0 ) {
    395441        $message = '';
    396         $post_id = self::find_product( $item['sku'] );
     442        $post_id = empty( $post_id ) ? $post_id : self::find_product( $item['sku'] );
    397443        if ( ! $post_id ) {
    398444            $post_id = self::create_product_post( $settings, $item );
     
    404450            $result_prod = self::sync_product( $settings, $item, $api_erp, $post_id, 'simple', null );
    405451            $post_id     = $result_prod['prod_id'] ?? 0;
     452
     453            // Add custom taxonomies.
     454            self::add_custom_taxonomies( $post_id, $item );
    406455        }
    407456        if ( $from_pack ) {
     
    456505            }
    457506        }
     507
     508        // Add custom taxonomies.
     509        self::add_custom_taxonomies( $product_id, $item );
    458510
    459511        // Remove variations without SKU blank.
     
    491543            }
    492544            // Make Variations.
    493             if ( 'default' === $rate_id || '' === $rate_id ) {
    494                 if ( isset( $variant['price'] ) && $variant['price'] ) {
    495                     $variation_price = $variant['price'];
    496                 } else {
    497                     $variation_price = 0;
    498                 }
    499             } else {
    500                 $variant_price_key = array_search( $rate_id, array_column( $variant['rates'], 'id' ) );
    501                 $variation_price   = $variant['rates'][ $variant_price_key ]['subtotal'];
    502             }
     545            $variation_price   = self::get_rate_price( $variant, $rate_id );
    503546            $variation_props = array(
    504547                'parent_id'     => $product_id,
     
    506549                'regular_price' => $variation_price,
    507550            );
     551
     552            $price_sale = self::get_sale_price( $variant, $settings );
     553            if ( ! empty( $price_sale ) ) {
     554                $variation_props['sale_price'] = $price_sale;
     555            }
    508556            if ( 0 === $variation_id ) {
    509557                // New variation.
     
    522570            }
    523571            $variation = new \WC_Product_Variation( $variation_id );
     572            if ( ! empty( $variant['barcode'] ) ) {
     573                try {
     574                    $variation->set_global_unique_id( $item['barcode'] );
     575                } catch ( \Exception $e ) {
     576                    // Error.
     577                }
     578            }
    524579            $variation->set_props( $variation_props );
    525580            // Stock.
     
    721776     * @return string $product_id Products id.
    722777     */
    723     public static function find_product( $sku ) {
     778    public static function find_product( $sku, $post_type = 'product' ) {
    724779        global $wpdb;
    725         $post_type    = 'product';
    726780        $meta_key     = '_sku';
    727781        $result_query = $wpdb->get_var( $wpdb->prepare( "SELECT P.ID FROM $wpdb->posts AS P LEFT JOIN $wpdb->postmeta AS PM ON PM.post_id = P.ID WHERE P.post_type = '$post_type' AND PM.meta_key='$meta_key' AND PM.meta_value=%s AND P.post_status != 'trash' LIMIT 1", $sku ) );
     
    737791     */
    738792    public static function find_parent_product( $sku ) {
    739         global $wpdb;
    740         $post_id_var = $wpdb->get_var( $wpdb->prepare( "SELECT post_id FROM $wpdb->postmeta WHERE meta_key='_sku' AND meta_value=%s LIMIT 1", $sku ) );
     793        $post_id_var = self::find_product( $sku, 'product_variation' );
    741794
    742795        if ( $post_id_var ) {
    743             $post_parent = wp_get_post_parent_id( $post_id_var );
     796            $post_parent = wp_get_post_parent_id( (int) $post_id_var );
    744797            return $post_parent;
    745798        }
     
    808861     * Gets image from API products
    809862     *
    810      * @param string $item_id Id of API to get information.
     863     * @param string $item Item of API to get information.
    811864     * @param string $product_id Id of product to get information.
    812865     * @param object $api_erp API Object.
    813866     *
    814      * @return array Array of products imported via API.
    815      */
    816     public static function put_product_image( $settings, $item_id, $product_id, $api_erp ) {
    817         // Don't import if there is thumbnail.
    818         if ( has_post_thumbnail( $product_id ) ) {
     867     * @return void
     868     */
     869    public static function put_product_images( $settings, $item, $product_id, $api_erp ) {
     870        if ( self::has_valid_thumbnail( $product_id ) ) {
    819871            return false;
    820872        }
    821873
    822         $result_api = $api_erp->get_image_product( $settings, $item_id, $product_id );
    823 
    824         if ( isset( $result_api['upload']['url'] ) ) {
    825             $attachment = array(
    826                 'guid'           => $result_api['upload']['url'],
    827                 'post_mime_type' => $result_api['content_type'],
    828                 'post_title'     => get_the_title( $product_id ),
    829                 'post_content'   => '',
    830                 'post_status'    => 'inherit',
    831             );
    832             $attach_id  = wp_insert_attachment( $attachment, $result_api['upload']['file'], 0 );
    833             add_post_meta( $product_id, '_thumbnail_id', $attach_id, true );
     874        $images = array();
     875        if ( ! empty( $item['images'] ) ) {
     876            $images = $item['images'] ?? array();
     877        } else {
     878            // Ask API for image.
     879            $result_api = $api_erp->get_image_product( $settings, $item['id'], $product_id );
    834880
    835881            if ( isset( $body_response['errors'] ) ) {
     
    838884                return false;
    839885            }
    840 
    841             return $attach_id;
     886            if ( isset( $result_api['upload']['url'] ) ){
     887                $images[] = [
     888                    'url'          => $result_api['upload']['url'],
     889                    'file'         => $result_api['upload']['file'],
     890                    'content_type' => $result_api['content_type'],
     891                ];
     892            }
     893        }
     894
     895        if ( empty( $images ) ) {
     896            return;
     897        }
     898
     899        $first_image = true;
     900        foreach ( $images as $image ) {
     901            $attachment = array(
     902                'guid'           => $image['url'] ?? '',
     903                'post_mime_type' => $image['content_type'] ?? '',
     904                'post_title'     => $image['title'] ?? get_the_title( $product_id ),
     905                'post_content'   => $image['content'] ?? '',
     906                'post_status'    => 'inherit',
     907            );
     908
     909            if ( empty( $image['file'] ) ) {
     910                // Download image to server
     911                $image_url = $image['url'] ?? '';
     912                if ( empty( $image_url ) ) {
     913                    continue;
     914                }
     915
     916                $file_array = [];
     917                $file_array['name'] = basename( $image_url );
     918                $file_array['tmp_name'] = download_url( $image_url );
     919
     920                // Check for download errors
     921                if ( is_wp_error( $file_array['tmp_name'] ) ) {
     922                    continue;
     923                }
     924
     925                $attach_id = media_handle_sideload( $file_array, $product_id, $attachment['post_title'], $attachment );
     926
     927                // Check for attachment errors
     928                if (is_wp_error($attach_id)) {
     929                    @unlink($file_array['tmp_name']);
     930                    continue;
     931                }
     932            } else {
     933                if ( ! file_exists( $image['file'] ) ) {
     934                    continue;
     935                }
     936
     937                $attach_id  = wp_insert_attachment( $attachment, $image['file'], 0 );
     938            }
     939
     940            if ( $first_image ) {
     941                $first_image = false;
     942                // Set the product image.
     943                add_post_meta( $product_id, '_thumbnail_id', $attach_id, true );
     944            } else {
     945                // Add the image to the product gallery.
     946                $gallery = get_post_meta( $product_id, '_product_image_gallery', true );
     947                $gallery = $gallery ? $gallery . ',' . $attach_id : $attach_id;
     948                update_post_meta( $product_id, '_product_image_gallery', $gallery );
     949            }
    842950        }
    843951    }
     
    9561064        }
    9571065    }
     1066
     1067    /**
     1068     * Get sale price from item
     1069     *
     1070     * @param array $item Item from API.
     1071     * @param array $settings Settings of the plugin.
     1072     *
     1073     * @return string
     1074     */
     1075    private static function get_sale_price( $item, $settings ) {
     1076        $pricesale_discount = (float) $settings['pricesale_discount'] ?? 0;
     1077        if ( empty( $pricesale_discount ) || empty( $item['price'] ) ) {
     1078            return '';
     1079        }
     1080        $price_sale = $item['price'] - ( $item['price'] * ( $pricesale_discount / 100 ) );
     1081        if ( $price_sale > 0 ) {
     1082            return number_format( $price_sale, 2, '.', '' );
     1083        } else {
     1084            return '';
     1085        }
     1086    }
     1087
     1088    /**
     1089     * Get attribute category ID
     1090     *
     1091     * @param array $item Item from API.
     1092     *
     1093     * @return int
     1094     */
     1095    private static function get_rate_price( $item, $rate_id ) {
     1096        if ( empty( $item ) ) {
     1097            return null;
     1098        }
     1099        if ( 'default' === $rate_id || '' === $rate_id || empty( $item['rates'] ) || ! is_array( $item['rates'] ) ) {
     1100            return isset( $item['price'] ) ? $item['price'] : null;
     1101        } else {
     1102            $price_key = array_search( $rate_id, array_column( $item['rates'], 'id' ) );
     1103            return isset( $item['rates'][ $price_key ]['subtotal'] ) ? $item['rates'][ $price_key ]['subtotal'] : null;
     1104        }
     1105    }
     1106
     1107    /**
     1108     * Add custom taxonomies to product
     1109     *
     1110     * @param int   $product_id Product ID.
     1111     * @param array $item Item from API.
     1112     *
     1113     * @return void
     1114     */
     1115    private static function add_custom_taxonomies( $product_id, $item ) {
     1116        // Set taxonomies.
     1117        if ( ! empty( $item['taxonomies'] ) && is_array( $item['taxonomies'] ) ) {
     1118            foreach ( $item['taxonomies'] as $taxonomy ) {
     1119                if ( empty( $taxonomy['id'] ) || empty( $taxonomy['value'] ) ) {
     1120                    continue;
     1121                }
     1122                TAX::assign_product_term( $product_id, $taxonomy['id'], $taxonomy['value'], true );
     1123            }
     1124        }
     1125    }
     1126
     1127    /**
     1128     * Checks if product has a valid thumbnail.
     1129     *
     1130     * @param int $product_id Product ID.
     1131     * @return bool
     1132     */
     1133    private static function has_valid_thumbnail( $product_id ) {
     1134        $thumbnail_id = get_post_thumbnail_id( $product_id );
     1135        if ( ! $thumbnail_id ) {
     1136            return false;
     1137        }
     1138        $image_path = get_attached_file( $thumbnail_id );
     1139        if ( ! $image_path || ! file_exists( $image_path ) ) {
     1140            return false;
     1141        }
     1142        $image_url = wp_get_attachment_url( $thumbnail_id );
     1143        if ( ! $image_url ) {
     1144            return false;
     1145        }
     1146        return true;
     1147    }
    9581148}
  • connect-ecommerce/trunk/includes/Helpers/TAX.php

    r3281293 r3301423  
    218218     * @param string $post_id Post id of actual post id.
    219219     * @param array  $taxonomy_slug Slug of taxonomy.
    220      * @param array  $category_array Array of category.
     220     * @param array|string  $terms Array of terms.
    221221     * @return void
    222222     */
    223     private static function assign_product_term( $post_id, $taxonomy_slug, $category_array ) {
     223    public static function assign_product_term( $post_id, $taxonomy_slug, $terms ) {
    224224        $parent_term      = '';
    225         $term_levels      = count( $category_array );
     225        $terms                      = is_array( $terms ) ? $terms : array( $terms );
     226        $term_levels      = count( $terms );
    226227        $term_level_index = 1;
    227228
    228         foreach ( $category_array as $category_name ) {
    229             $category_name = self::sanitize_text( $category_name );
    230             $search_term   = term_exists( $category_name, $taxonomy_slug );
     229        foreach ( $terms as $term ) {
     230            $term        = self::sanitize_text( $term );
     231            $search_term = term_exists( $term, $taxonomy_slug );
    231232
    232233            if ( 0 === $search_term || null === $search_term ) {
    233234                // Creates taxonomy.
    234235                $args_term = array(
    235                     'slug' => sanitize_title( $category_name ),
     236                    'slug' => sanitize_title( $term ),
    236237                );
    237238                if ( $parent_term ) {
     
    239240                }
    240241                $search_term = wp_insert_term(
    241                     $category_name,
     242                    $term,
    242243                    $taxonomy_slug,
    243244                    $args_term
    244245                );
    245246            }
    246             if ( $term_level_index === $term_levels ) {
    247                 wp_set_object_terms( $post_id, (int) $search_term['term_id'], $taxonomy_slug );
     247           
     248            // Check if term was found or created successfully
     249            if ( ! is_wp_error( $search_term ) && $term_level_index === $term_levels ) {
     250                $term_id = isset( $search_term['term_id'] ) ? (int) $search_term['term_id'] : (int) $search_term;
     251                wp_set_object_terms( $post_id, $term_id, $taxonomy_slug );
    248252            }
    249253
    250254            // Next iteration for child.
    251             $parent_term = $search_term['term_id'];
     255            $parent_term = (int) $search_term['term_id'];
    252256            $term_level_index++;
    253257        }
     
    262266    private static function sanitize_text( $text ) {
    263267        $text = str_replace( '>', '&gt;', $text );
    264         return $text;
     268        return sanitize_text_field( $text );
    265269    }
    266270
  • connect-ecommerce/trunk/includes/Plugin_Main.php

    r3281293 r3301423  
    2828
    2929    /**
     30     * Options of plugin.
     31     *
     32     * @var array
     33     */
     34    private $options = array();
     35
     36    /**
    3037     * Construct of class
    3138     *
     
    3340     */
    3441    public function __construct( $options = array() ) {
     42        $this->options = $options;
    3543        if ( is_admin() ) {
    3644            new Settings( $options );
     
    4452        new MyAccount( $options );
    4553    }
     54
     55    /**
     56     * Get options of plugin.
     57     *
     58     * @return array
     59     */
     60    public function get_options( ) {
     61        return $this->options;
     62    }
    4663}
  • connect-ecommerce/trunk/includes/assets/sync-import.js

    r3281293 r3301423  
    4444}
    4545
    46 function syncProductERP( element, action, product_erp_id = 0, product_sku = '' ) {
     46function syncProductERP( element, action, product_erp_id = 0, product_sku = '', product_id = 0 ) {
    4747    element.classList.add('disabled');
    4848    element.innerHTML = ConEcom_ajaxAction.label_syncing + ' <span class="spinner is-active"></span>';
     
    5858            'Cache-Control': 'no-cache',
    5959        },
    60         body: 'action=' + action + '&nonce=' + ConEcom_ajaxAction.nonce + '&loop=' + loop + '&product_erp_id=' + product_erp_id + '&product_sku=' + product_sku + '&product_ai=' + productAI,
     60        body: 'action=' + action + '&nonce=' + ConEcom_ajaxAction.nonce + '&loop=' + loop + '&product_erp_id=' + product_erp_id + '&product_sku=' + product_sku + '&product_id=' + product_id + '&product_ai=' + productAI,
    6161    })
    6262    .then( (resp) => resp.json() )
     
    6565        element.innerHTML = ConEcom_ajaxAction.label_sync;
    6666
    67         // Refresh the page
    68         location.reload();
     67        console.log(results.data);
     68        // Message handling
     69        if (results.data.message !== undefined) {
     70            const aiInput = document.querySelector('#connect_ecommerce_ai');
     71            if (aiInput) {
     72                const aiLabel = aiInput.closest('label');
     73                const aiMessage = document.createElement('div');
     74                aiMessage.className = 'ai-message';
     75                aiMessage.innerHTML = results.data.message;
     76               
     77                const targetElement = aiLabel || aiInput;
     78                if (targetElement.nextSibling) {
     79                    targetElement.parentNode.insertBefore(aiMessage, targetElement.nextSibling);
     80                } else {
     81                    targetElement.parentNode.appendChild(aiMessage);
     82                }
     83            }
     84        }
     85
     86        // Reload the page after 8 seconds if the sync was successful
     87        if (results.success) {
     88            setTimeout(() => {
     89                window.location.reload();
     90            }, 8000);
     91        }
    6992    })
    7093    .catch(err => console.log(err));
  • connect-ecommerce/trunk/readme.txt

    r3289663 r3301423  
    4747[Official Repository GitHub](https://github.com/closemarketing/connect-ecommerce)
    4848
     49You can use WP CLI to import products from the command line. The command is:
     50```
     51wp conecom products --update --ai=none,new,all
     52```
     53
    4954== External services ==
    5055
     
    5964
    6065== Changelog ==
     66
     67= 3.1.0 =
     68* Added: WP CLI command to import products.
     69* Fully support to import EAN to WooCommerce.
     70* Added: Import image products with different method.
     71* Added: Result API import in widget product.
     72* Added: Save parent SKU in product if does not exist.
     73* Added: Check if image product file exists before import.
     74* Fixed: AI connection not working in some cases.
     75* Fixed: Some errors getting products from shop to syncronize.
     76* Fixed: Not getting prices rates from API.
     77* Fixed: Prevent error when WooCommerce does not load the product.
    6178
    6279= 3.0.1 =
  • connect-ecommerce/trunk/vendor/composer/installed.php

    r3289663 r3301423  
    22    'root' => array(
    33        'name' => 'closemarketing/connect-ecommerce',
    4         'pretty_version' => '3.0.1',
    5         'version' => '3.0.1.0',
    6         'reference' => '4b85748d444a7a4ddea31f4494598d5fffd54f4a',
     4        'pretty_version' => '3.1.0',
     5        'version' => '3.1.0.0',
     6        'reference' => 'f3639f9784b938002847fc0b6395dc83d2c1b030',
    77        'type' => 'library',
    88        'install_path' => __DIR__ . '/../../',
     
    1212    'versions' => array(
    1313        'closemarketing/connect-ecommerce' => array(
    14             'pretty_version' => '3.0.1',
    15             'version' => '3.0.1.0',
    16             'reference' => '4b85748d444a7a4ddea31f4494598d5fffd54f4a',
     14            'pretty_version' => '3.1.0',
     15            'version' => '3.1.0.0',
     16            'reference' => 'f3639f9784b938002847fc0b6395dc83d2c1b030',
    1717            'type' => 'library',
    1818            'install_path' => __DIR__ . '/../../',
Note: See TracChangeset for help on using the changeset viewer.