Changeset 3439783
- Timestamp:
- 01/14/2026 06:39:09 PM (8 weeks ago)
- Location:
- perseo-software/trunk
- Files:
-
- 4 edited
-
PluginPerseo.php (modified) (22 diffs)
-
PluginPerseoClientes.php (modified) (2 diffs)
-
README.md (modified) (1 diff)
-
includes/PluginPerseo_cron.php (modified) (53 diffs)
Legend:
- Unmodified
- Added
- Removed
-
perseo-software/trunk/PluginPerseo.php
r3270560 r3439783 4 4 Plugin URI: https://perseo.ec/ 5 5 Description: Este Plugins integra el Sistema Contable Perseo Web y PC con la tienda Woocommerce 6 Version: 3 2.06 Version: 33.0 7 7 Author: Perseo Soft S.A. - Ecuador 8 8 Author URI: https://perseo.ec … … 13 13 */ 14 14 15 $version_Plugin = '3 2.0';15 $version_Plugin = '33.0'; 16 16 define('PERSEO_DIR_PATH', plugin_dir_path(__FILE__)); 17 define('PERSEOCONFIGBASE', get_option('pluginperseo_configuracion')); 18 define('PERSEOCONFIGPARAMETROS', get_option('pluginperseo_parametros')); 17 18 $perseo_config_temp = get_option('pluginperseo_configuracion'); 19 $perseo_parametros_temp = get_option('pluginperseo_parametros'); 20 21 define('PERSEOCONFIGBASE', is_array($perseo_config_temp) ? $perseo_config_temp : []); 22 define('PERSEOCONFIGPARAMETROS', is_array($perseo_parametros_temp) ? $perseo_parametros_temp : []); 23 24 function fperseo_get_config() { 25 $config = get_option('pluginperseo_configuracion', []); 26 return is_array($config) ? $config : []; 27 } 28 29 function fperseo_get_parametros() { 30 $parametros = get_option('pluginperseo_parametros', []); 31 return is_array($parametros) ? $parametros : []; 32 } 19 33 20 34 function pluginperseo_install() … … 56 70 // Opcional: Forzar la eliminación de caché de transients 57 71 wp_cache_flush(); 72 } 73 74 // Función para limpiar transients de bloqueo de Perseo 75 function fperseo_limpiar_transients() 76 { 77 global $wpdb; 78 79 // Verificar permisos y nonce 80 if (!current_user_can('manage_options')) { 81 return false; 82 } 83 84 if (!isset($_POST['perseo_limpiar_nonce']) || !wp_verify_nonce($_POST['perseo_limpiar_nonce'], 'perseo_limpiar_transients')) { 85 return false; 86 } 87 88 // Eliminar transients de bloqueo de Perseo (usar $wpdb->options directamente) 89 $eliminados_transients = $wpdb->query( 90 "DELETE FROM {$wpdb->options} WHERE option_name LIKE '_transient_perseo_cron_bloqueo_%'" 91 ); 92 $eliminados_timeouts = $wpdb->query( 93 "DELETE FROM {$wpdb->options} WHERE option_name LIKE '_transient_timeout_perseo_cron_bloqueo_%'" 94 ); 95 96 // Limpiar caché 97 wp_cache_flush(); 98 99 return $eliminados_transients + $eliminados_timeouts; 100 } 101 add_action('admin_post_perseo_limpiar_transients', 'fperseo_limpiar_transients'); 102 103 // Función para obtener transients activos de Perseo 104 function fperseo_obtener_transients_activos() 105 { 106 global $wpdb; 107 108 $transients = $wpdb->get_results( 109 "SELECT option_name, option_value 110 FROM {$wpdb->options} 111 WHERE option_name LIKE '_transient_perseo_cron_bloqueo_%' 112 AND option_name NOT LIKE '_transient_timeout_%'" 113 ); 114 115 return $transients; 58 116 } 59 117 … … 123 181 settings_errors('eperseo_verificacion'); 124 182 /////////////////////////////////////////////////////////////////////// 125 //llamamos a la pag de secciones 183 //llamamos a la pag de secciones 126 184 //validamos el formulario y enviamos valores para redirigir a la pag perseo 127 185 echo "<form action='options.php' method='post'> "; … … 129 187 do_settings_sections('pluginperseo_menu'); 130 188 submit_button('Guardar Cambios'); 131 //submit_button('Guardar Cambios','primary','submit', true, array('id'=>'perseoconexion', 'onclick'=>'perseotestconec()')); 189 //submit_button('Guardar Cambios','primary','submit', true, array('id'=>'perseoconexion', 'onclick'=>'perseotestconec()')); 132 190 echo "</form>"; 133 191 /////////////////////////////////////////////////////////////////////// 134 //TEST de conexion 135 //echo "<p id='perseovalidarconexion'></p>"; 192 //TEST de conexion 193 //echo "<p id='perseovalidarconexion'></p>"; 136 194 } 137 195 } … … 157 215 settings_errors('eperseo_verificacion'); 158 216 /////////////////////////////////////////////////////////////////////// 159 //llamamos a la pag de secciones 217 //llamamos a la pag de secciones 160 218 //validamos el formulario y enviamos valores para redirigir a la pag perseo 161 219 echo "<form action='options.php' method='post' > "; … … 175 233 ////////////////////////////////////////////////////////////////////// 176 234 /// Api settings 177 /// permiso para guardar configuraciones 235 /// permiso para guardar configuraciones 178 236 function fperseo_plugininicio() 179 237 { … … 420 478 function sperseo_seccionencabezado() 421 479 { 480 global $wpdb; 481 482 // 🔹 Procesar limpieza ANTES de todo (usando GET en lugar de POST) 483 $mensaje_limpieza = ''; 484 if (isset($_GET['perseo_limpiar']) && $_GET['perseo_limpiar'] == '1') { 485 if (isset($_GET['_wpnonce']) && wp_verify_nonce($_GET['_wpnonce'], 'perseo_limpiar_transients') && current_user_can('manage_options')) { 486 487 $eliminados_transients = $wpdb->query( 488 "DELETE FROM {$wpdb->options} WHERE option_name LIKE '_transient_perseo_cron_bloqueo_%'" 489 ); 490 $eliminados_timeouts = $wpdb->query( 491 "DELETE FROM {$wpdb->options} WHERE option_name LIKE '_transient_timeout_perseo_cron_bloqueo_%'" 492 ); 493 494 wp_cache_flush(); 495 496 $total = $eliminados_transients + $eliminados_timeouts; 497 $mensaje_limpieza = "<div class='notice notice-success is-dismissible'><p><strong>Limpieza completada:</strong> Se eliminaron {$total} registros de bloqueo.</p></div>"; 498 } 499 } 500 501 // Mostrar mensaje si existe 502 if (!empty($mensaje_limpieza)) { 503 echo $mensaje_limpieza; 504 } 505 422 506 echo "<p><b>Sincronizacion de Perseo Software a WordPress :</b><br> Clientes, Productos, Productos Categorias , Productos Imagenes y Productos Stock. </p>"; 423 507 echo "<p><b>Sincronizacion de WordPress a Perseo Software : </b><br> Clientes, Pedidos.</p>"; … … 425 509 echo "<p><b>Datos Servidor </b> <br> Version PHP " . phpversion() . " " . $_SERVER['SERVER_SOFTWARE'] . "</p>"; 426 510 echo "<h3> Conexion Perseo Software </h3>"; 427 ///////////////////////////// 428 /// wp_cron 429 /* 430 echo '<pre>'; 431 var_dump(wp_get_schedules()); 432 433 var_dump(_get_cron_array()); 434 echo '</pre>'; 435 */ 511 512 // Obtener transients activos 513 $transients_activos = fperseo_obtener_transients_activos(); 514 515 echo "<hr style='margin: 20px 0;'>"; 516 echo "<h3>Estado de Procesos Cron</h3>"; 517 518 if (!empty($transients_activos)) { 519 echo "<div class='notice notice-warning'>"; 520 echo "<p><strong>⚠️ Procesos bloqueados o en ejecución:</strong></p>"; 521 echo "<table class='widefat' style='max-width: 500px;'>"; 522 echo "<thead><tr><th>Proceso</th><th>Estado</th></tr></thead>"; 523 echo "<tbody>"; 524 foreach ($transients_activos as $transient) { 525 $nombre_proceso = str_replace('_transient_perseo_cron_bloqueo_', '', $transient->option_name); 526 echo "<tr><td><code>{$nombre_proceso}</code></td><td>🔒 Bloqueado</td></tr>"; 527 } 528 echo "</tbody></table>"; 529 echo "</div>"; 530 } else { 531 echo "<div class='notice notice-success'><p>✅ No hay procesos bloqueados. Todo está funcionando correctamente.</p></div>"; 532 } 533 534 // 🔹 Botón usando enlace GET en lugar de formulario POST (evita conflictos) 535 $nonce = wp_create_nonce('perseo_limpiar_transients'); 536 $url_limpiar = admin_url('admin.php?page=mperseo_menupage&perseo_limpiar=1&_wpnonce=' . $nonce); 537 538 $btn_class = !empty($transients_activos) ? 'button button-primary' : 'button button-secondary'; 539 $btn_text = !empty($transients_activos) ? '🗑️ Limpiar Bloqueos (' . count($transients_activos) . ')' : '🗑️ Limpiar Bloqueos'; 540 $btn_disabled = empty($transients_activos) ? 'disabled' : ''; 541 542 echo "<div style='margin-top: 15px;'>"; 543 if (!empty($transients_activos)) { 544 echo "<a href='{$url_limpiar}' class='{$btn_class}' onclick=\"return confirm('¿Estás seguro de eliminar todos los bloqueos? Solo hazlo si un proceso se quedó colgado.');\">{$btn_text}</a>"; 545 } else { 546 echo "<button type='button' class='{$btn_class}' disabled>{$btn_text}</button>"; 547 } 548 echo "<p class='description' style='margin-top: 10px;'>Usa este botón <strong>solo</strong> si un proceso de sincronización se quedó bloqueado y no permite ejecutar nuevas sincronizaciones.</p>"; 549 echo "</div>"; 550 551 echo "<hr style='margin: 20px 0;'>"; 436 552 } 437 553 function sperseo_seccionencabezado1() … … 463 579 echo $perseo_html; 464 580 } 581 465 582 function fperseo_certificado($args) 466 583 { … … 517 634 function fperseo_servidor($args) 518 635 { 519 $perseo_config = PERSEOCONFIGBASE; //parametros de conexion 636 $perseo_config = PERSEOCONFIGBASE; //parametros de conexion 520 637 $perseo_activar = ''; 521 638 if (isset($perseo_config['perseotiposoftware'])) { … … 555 672 foreach ($perseo_datosServidores as $servidor) { 556 673 // echo $registro['sis_servidoresid']; 557 // echo "<br>"; 674 // echo "<br>"; 558 675 $perseo_refr1 = ($perseo_config[$args['label_for']] == ($servidor['dominio'])) ? $perseo_selec : ''; 559 676 … … 573 690 function fperseo_impuestos($args) 574 691 { 575 $perseo_parametros = PERSEOCONFIGPARAMETROS; // parametrizacion 692 $perseo_parametros = PERSEOCONFIGPARAMETROS; // parametrizacion 576 693 //condcion si existe valiable los dos puntos caso de sino es valor2=10 ? true : false 577 694 //$perseo_selec='selected'; … … 593 710 echo $perseo_html; 594 711 } 712 595 713 function fperseo_productos($args) 596 714 { 597 $perseo_parametros = PERSEOCONFIGPARAMETROS; // parametrizacion 715 $perseo_parametros = PERSEOCONFIGPARAMETROS; // parametrizacion 598 716 //condcion si existe valiable los dos puntos caso de sino es valor2=10 ? true : false 599 717 $perseo_selec = 'selected'; … … 610 728 echo $perseo_html; 611 729 } 730 612 731 function fperseo_imagenes($args) 613 732 { 614 733 615 $perseo_parametros = PERSEOCONFIGPARAMETROS; // parametrizacion 734 $perseo_parametros = PERSEOCONFIGPARAMETROS; // parametrizacion 616 735 //condcion si existe valiable los dos puntos caso de sino es valor2=10 ? true : false 617 736 $perseo_selec = 'selected'; … … 628 747 echo $perseo_html; 629 748 } 749 630 750 function fperseo_stock($args) 631 751 { 632 $perseo_parametros = PERSEOCONFIGPARAMETROS; // parametrizacion 752 $perseo_parametros = PERSEOCONFIGPARAMETROS; // parametrizacion 633 753 //condcion si existe valiable los dos puntos caso de sino es valor2=10 ? true : false 634 754 $perseo_selec = 'selected'; … … 645 765 echo $perseo_html; 646 766 } 767 647 768 function fperseo_clientes($args) 648 769 { 649 770 650 $perseo_parametros = PERSEOCONFIGPARAMETROS; // parametrizacion 771 $perseo_parametros = PERSEOCONFIGPARAMETROS; // parametrizacion 651 772 //condcion si existe valiable los dos puntos caso de sino es valor2=10 ? true : false 652 773 $perseo_selec = 'selected'; … … 663 784 echo $perseo_html; 664 785 } 786 665 787 function fperseo_pedidos($args) 666 788 { 667 789 668 $perseo_parametros = PERSEOCONFIGPARAMETROS; // parametrizacion 790 $perseo_parametros = PERSEOCONFIGPARAMETROS; // parametrizacion 669 791 //condcion si existe valiable los dos puntos caso de sino es valor2=10 ? true : false 670 792 $perseo_selec = 'selected'; … … 681 803 echo $perseo_html; 682 804 } 805 683 806 function fperseo_categorias($args) 684 807 { … … 703 826 } 704 827 705 706 707 828 function fperseo_enviarclientes($args) 708 829 { 709 $perseo_parametros = PERSEOCONFIGPARAMETROS; // parametrizacion 830 $perseo_parametros = PERSEOCONFIGPARAMETROS; // parametrizacion 710 831 //condcion si existe valiable los dos puntos caso de sino es valor2=10 ? true : false 711 832 $perseo_selec = 'selected'; … … 740 861 echo $perseo_html; 741 862 } 863 742 864 function fperseo_sincronizar($args) 743 865 { … … 757 879 function fperseo_tarifaventa($args) 758 880 { 759 $perseo_config = PERSEOCONFIGBASE; //parametros de conexion 760 $perseo_parametros = PERSEOCONFIGPARAMETROS; // parametrizacion 881 $perseo_config = PERSEOCONFIGBASE; 882 $perseo_parametros = get_option('pluginperseo_parametros'); 883 884 // 🔹 Validar que sean arrays 885 if (!is_array($perseo_parametros)) { 886 $perseo_parametros = []; 887 } 761 888 762 889 if (!empty($perseo_config['perseotoken'])) { 763 /////////////////////////////////////////// 764 //Consulta APi 765 $perseo_selec = 'selected'; 766 ///////////////////////////////////// 767 //Verificar pc o web 768 if ($perseo_config['perseotiposoftware'] == 'WEB') { 769 // $perseo_urltarifas =$perseo_config['perseoservidor'].''.'/api/tarifas_consulta'; 770 $perseo_urltarifas = $perseo_config['perseoservidor'] . '/api/tarifas_consulta'; 890 $perseo_selec = 'selected'; 891 892 if (isset($perseo_config['perseotiposoftware']) && $perseo_config['perseotiposoftware'] == 'WEB') { 893 $perseo_urltarifas = $perseo_config['perseoservidor'] . '/api/tarifas_consulta'; 771 894 } else { 772 $perseo_urltarifas = $perseo_config['perseocertificado'] . '://' . $perseo_config['perseoip']. '/api/tarifas_consulta';895 $perseo_urltarifas = ($perseo_config['perseocertificado'] ?? 'http') . '://' . ($perseo_config['perseoip'] ?? '') . '/api/tarifas_consulta'; 773 896 } 774 $datoKEY = [ 775 'api_key' => $perseo_config['perseotoken'] 776 ]; 897 898 $datoKEY = ['api_key' => $perseo_config['perseotoken']]; 777 899 $perseo_responsetarifas = wp_remote_post($perseo_urltarifas, array( 778 'method' => 'POST',779 'headers' => array('Content-Type' => 'application/json'),780 'body' => wp_json_encode($datoKEY)900 'method' => 'POST', 901 'headers' => array('Content-Type' => 'application/json'), 902 'body' => wp_json_encode($datoKEY) 781 903 )); 782 // presentar datos783 //print_r($perseo_responsetarifas);784 //print_r($perseo_responsetarifas['body']);785 904 786 905 $perseo_muestra = ""; 787 if (!empty($perseo_responsetarifas)) { 788 if (is_wp_error($perseo_responsetarifas)) { 789 echo "<p>Existe problemas en conexion de Api Perseo<p>"; 790 } else { 791 if (!empty($perseo_responsetarifas['body'])) { 792 $perseo_datosTarifas = json_decode($perseo_responsetarifas['body'], true); //devuelve 793 // si es diferente de vacio 794 if (isset($perseo_datosTarifas)) { 795 foreach ($perseo_datosTarifas as $registro) { 906 if (!empty($perseo_responsetarifas) && !is_wp_error($perseo_responsetarifas)) { 907 if (!empty($perseo_responsetarifas['body'])) { 908 $perseo_datosTarifas = json_decode($perseo_responsetarifas['body'], true); 909 if (isset($perseo_datosTarifas) && is_array($perseo_datosTarifas)) { 910 foreach ($perseo_datosTarifas as $registro) { 911 if (is_array($registro)) { 796 912 foreach ($registro as $tarifa) { 797 913 $perseo_refr1 = isset($perseo_parametros[$args['label_for']]) ? (($perseo_parametros[$args['label_for']] == ($tarifa['tarifasid'])) ? $perseo_selec : '') : ''; 798 $perseo_muestra = $perseo_muestra . " <option value='" . $tarifa['tarifasid'] . "' " . $perseo_refr1 . " >" . $tarifa['descripcion'] . "</option>'";914 $perseo_muestra .= " <option value='" . $tarifa['tarifasid'] . "' " . $perseo_refr1 . " >" . $tarifa['descripcion'] . "</option>"; 799 915 } 800 916 } 801 }; 802 803 $perseo_parametros = get_option('pluginperseo_parametros'); 804 //condcion si existe valiable los dos puntos caso de sino es 805 $perseo_parametros[$args['label_for']] = isset($perseo_parametros[$args['label_for']]) ? esc_attr($perseo_parametros[$args['label_for']]) : ''; 806 807 $perseo_html = "<select class='{$args['class']}' data-custom='{$args['perseo_datopersonalizado']}' name='pluginperseo_parametros[{$args['label_for']}]' > " . $perseo_muestra . " </select >"; 808 809 echo $perseo_html; 917 } 810 918 } 811 }; 919 920 $valor_actual = isset($perseo_parametros[$args['label_for']]) ? esc_attr($perseo_parametros[$args['label_for']]) : ''; 921 922 $perseo_html = "<select class='{$args['class']}' data-custom='{$args['perseo_datopersonalizado']}' name='pluginperseo_parametros[{$args['label_for']}]'>" . $perseo_muestra . "</select>"; 923 echo $perseo_html; 924 } 925 } else { 926 echo "<p>Existe problemas en conexion de Api Perseo</p>"; 812 927 } 813 928 } 814 929 } 930 815 931 // Parametro Servidor 816 817 //818 932 function fperseo_tarifaAumento($args) 819 933 { 820 $perseo_config = PERSEOCONFIGBASE; //parametros de conexion 821 $perseo_parametros = PERSEOCONFIGPARAMETROS; // parametrizacion 934 $perseo_config = PERSEOCONFIGBASE; 935 $perseo_parametros = get_option('pluginperseo_parametros'); 936 937 // 🔹 Validar que sean arrays 938 if (!is_array($perseo_parametros)) { 939 $perseo_parametros = []; 940 } 941 822 942 if (!empty($perseo_config['perseotoken'])) { 823 ///////////////////////////////////////////824 //Consulta APi825 943 $perseo_selec = 'selected'; 826 ///////////////////////////////////// 827 //Verificar pc o web 828 if ($perseo_config['perseotiposoftware'] == 'WEB') { 829 $perseo_urltarifas = $perseo_config['perseoservidor'] . '/api/tarifas_consulta'; 944 945 if (isset($perseo_config['perseotiposoftware']) && $perseo_config['perseotiposoftware'] == 'WEB') { 946 $perseo_urltarifas = $perseo_config['perseoservidor'] . '/api/tarifas_consulta'; 830 947 } else { 831 $perseo_urltarifas = $perseo_config['perseocertificado'] . '://' . $perseo_config['perseoip']. '/api/tarifas_consulta';948 $perseo_urltarifas = ($perseo_config['perseocertificado'] ?? 'http') . '://' . ($perseo_config['perseoip'] ?? '') . '/api/tarifas_consulta'; 832 949 } 950 833 951 $datoKEY = ['api_key' => $perseo_config['perseotoken']]; 834 835 952 $perseo_responsetarifas = wp_remote_post($perseo_urltarifas, array( 836 'method' => 'POST',837 'headers' => array('Content-Type' => 'application/json'),838 'body' => wp_json_encode($datoKEY)953 'method' => 'POST', 954 'headers' => array('Content-Type' => 'application/json'), 955 'body' => wp_json_encode($datoKEY) 839 956 )); 840 // print_r($perseo_responsetarifas); 957 841 958 $perseo_muestra = ""; 842 if (!empty($perseo_responsetarifas)) { 843 if (is_wp_error($perseo_responsetarifas)) { 844 echo "<p>Existe problemas en conexion de Api Perseo<p>"; 845 } else { 846 if (!empty($perseo_responsetarifas['body'])) { 847 //if (isset($perseo_responsetarifas['body']['tarifas'])){ 848 $perseo_datosTarifas = json_decode($perseo_responsetarifas['body'], true); //devuelve 849 if (isset($perseo_datosTarifas)) { 850 foreach ($perseo_datosTarifas as $registro) { 959 if (!empty($perseo_responsetarifas) && !is_wp_error($perseo_responsetarifas)) { 960 if (!empty($perseo_responsetarifas['body'])) { 961 $perseo_datosTarifas = json_decode($perseo_responsetarifas['body'], true); 962 if (isset($perseo_datosTarifas) && is_array($perseo_datosTarifas)) { 963 foreach ($perseo_datosTarifas as $registro) { 964 if (is_array($registro)) { 851 965 foreach ($registro as $tarifa) { 852 966 $perseo_refr1 = isset($perseo_parametros[$args['label_for']]) ? (($perseo_parametros[$args['label_for']] == ($tarifa['tarifasid'])) ? $perseo_selec : '') : ''; 853 $perseo_muestra = $perseo_muestra . " <option value='" . $tarifa['tarifasid'] . "' " . $perseo_refr1 . " >" . $tarifa['descripcion'] . "</option>'";967 $perseo_muestra .= " <option value='" . $tarifa['tarifasid'] . "' " . $perseo_refr1 . " >" . $tarifa['descripcion'] . "</option>"; 854 968 } 855 969 } 856 }; 857 //echo $muestra; 858 //condcion si existe valiable los dos puntos caso de sino es 859 $perseo_parametros[$args['label_for']] = isset($perseo_parametros[$args['label_for']]) ? esc_attr($perseo_parametros[$args['label_for']]) : ''; 860 861 $perseo_html = "<select class='{$args['class']}' data-custom='{$args['perseo_datopersonalizado']}' name='pluginperseo_parametros[{$args['label_for']}]' >" . $perseo_muestra . " </select >"; 862 863 echo $perseo_html; 864 //} 865 } else { 866 echo "<p>No existe conexion con Api Perseo<p>"; 970 } 867 971 } 972 973 $valor_actual = isset($perseo_parametros[$args['label_for']]) ? esc_attr($perseo_parametros[$args['label_for']]) : ''; 974 975 $perseo_html = "<select class='{$args['class']}' data-custom='{$args['perseo_datopersonalizado']}' name='pluginperseo_parametros[{$args['label_for']}]'>" . $perseo_muestra . "</select>"; 976 echo $perseo_html; 868 977 } 978 } else { 979 echo "<p>No existe conexion con Api Perseo</p>"; 869 980 } 870 981 } 871 982 } 872 873 874 983 875 984 ///////////////////////////////////// -
perseo-software/trunk/PluginPerseoClientes.php
r3270560 r3439783 1 1 <?php 2 $version_Plugin = '32.0'; 3 //define('PERSEO_DIR_PATH', plugin_dir_path(__FILE__)); 4 //////////////////////////////////////////////////////////////// 5 //////Anadir campos Cedula al registro mediante Woocommerce//// 6 ////// de cedula para guardar y enviar a perseo ///// 7 ///////////////////////////////////////////////////////////// 8 /* 9 <p class="woocommerce-form-row woocommerce-form-row--wide form-row form-row-wide" > 10 <label for="tipoIdentificacion">Tipo</label> 11 <select class="woocommerce-Input " id="tipoIdentificacion" name="tipoIdentificacion"> 12 <option value="C">RUC</option> 13 <option value="R">Cedula</option> 14 <option value="P">Pasaporte</option> 15 </select > 16 </p> 17 */ 2 $version_Plugin = '33.0'; 18 3 19 4 function campos_adicionales_registro_usuario() … … 55 40 $errors->add('PerseoIdentificacion_error', __(' Identificacion no puede estar vacia', 'textdomain')); 56 41 } else { 57 //verificar si ya existe esta cedula 42 //verificar si ya existe esta cedula 58 43 $perseo_IngresoIdent = $wpdb->get_var("SELECT user.user_id as id FROM {$table_prefix}usermeta as user where user.meta_key='PerseoIdentificacion' and user.meta_value like '%" . $_POST['PerseoIdentificacion'] . "%'"); 59 44 //$errors->add('PerseoIdentificacion_error', __('<strong>Error</strong>: Identificacion ya existe-'.$perseo_IngresoIdent, 'textdomain')); -
perseo-software/trunk/README.md
r3270560 r3439783 1 === P luginPerseo===1 === Perseo Software === 2 2 3 3 Contributors: Perseo Soft S.A. - Ecuador 4 4 Donate Link: https://perseo.ec/ 5 Tags: auto publish, content marketing6 Requires at least: 1.15 Tags: woocommerce, erp, sync, inventory, perseo, accounting, ecommerce 6 Requires at least: 5.0 7 7 Tested up to: 6.7.2 8 8 Requires PHP: 7.4 9 Stable tag: 3 2.09 Stable tag: 33.0 10 10 License: GPLv2 or later 11 11 License URI: http://www.gnu.org/licenses/gpl-2.0.html 12 12 13 This Pluing integrates the Accounting System Perseo Web and PC with the store. 13 Integra el Sistema Contable Perseo (Web y PC) con tu tienda WooCommerce. Sincroniza productos, clientes, inventario y pedidos automáticamente. 14 14 15 == Description == 15 16 16 [PluginPerseo Content](http://perseo.ec/) is a native WordPress plugin that integrates with the Perseo Accounting System. It has been designed to help you efficiently create and promote the content of your online store by automatically synchronizing the products registered in your system. Run a successful blog while saving tons of time..17 **Perseo Software** es un plugin nativo de WordPress que conecta tu tienda WooCommerce con el Sistema Contable Perseo, permitiendo una sincronización automática y eficiente de tu negocio. 17 18 18 Perseo Software Plugin: 19 = ✨ Características Principales = 19 20 20 -Installation of the WooCommerce Plugin. 21 * **Sincronización de Productos** - Importa automáticamente productos desde Perseo incluyendo precios, stock e imágenes 22 * **Gestión de Clientes** - Sincroniza clientes entre WordPress y Perseo en ambas direcciones 23 * **Control de Inventario** - Mantén tu stock actualizado 24 * **Envío de Pedidos** - Los pedidos de WooCommerce se envían automáticamente a Perseo 25 * **Categorías Automáticas** - Sincroniza categorías, líneas, subcategorías o subgrupos 26 * **Múltiples Tarifas** - Configura precio normal y precio rebajado desde Perseo 27 * **Impuestos** - Sincronización automática de tipos de IVA 21 28 22 -Synchronization of Perseo to WordPress: clients-categories -products. 29 = 🔄 Sincronización = 23 30 24 -Synchronization from WordPress to Perseus: 25 orders. 31 **De Perseo a WordPress:** 32 - Productos (descripción, precios, stock, imágenes) 33 - Categorías / Líneas / Subcategorías / Subgrupos 34 - Clientes 35 - Impuestos (IVA) 26 36 27 Product images must be square photos. Example 1080x1080px. 37 **De WordPress a Perseo:** 38 - Clientes nuevos 39 - Pedidos (estado "Procesando") 40 41 = ⚙️ Requisitos = 42 43 * WordPress 5.0 o superior 44 * WooCommerce instalado y activo 45 * PHP 7.4 o superior 46 * Perseo Web o Perseo PC con API habilitada 47 * Token de API de Perseo 28 48 29 49 == Installation == 30 50 31 Contact your Perseo Software support. 51 1. Ve a **Perseo Software** en el menú de administración 52 2. Configura tu conexión (Token, Servidor) 53 3. Ve a **Parametrización** y activa las sincronizaciones que necesites 32 54 33 55 == Frequently Asked Questions == 34 56 35 = A question that someone might have=57 = ¿Qué versión de Perseo necesito? = 36 58 37 An answer to that question.59 El plugin funciona con Perseo Web y Perseo PC. Necesitas tener habilitada la API y un token válido. 38 60 39 = What about foo bar? =61 = ¿Cada cuánto tiempo se sincroniza? = 40 62 41 Answer to foo bar dilemma.63 Puedes configurar el intervalo de sincronización en minutos desde la Parametrización. Se recomienda entre 30 y 60 minutos. 42 64 43 = = Screenshots ==65 = ¿Los pedidos se envían automáticamente? = 44 66 45 1. perseo-1.jpg 46 2. == Changelog == 47 = 32.0 = 67 Sí, los pedidos con estado "Procesando" se envían automáticamente a Perseo en cada sincronización. 48 68 49 - Correcciones de sincronizacion de imagenes 69 = ¿Qué pasa si un producto se desactiva en Perseo? = 70 71 El producto se cambia a estado borrador (draft) en WooCommerce y no aparece en la tienda. Si se reactiva en Perseo, volverá a publicarse automáticamente. 72 73 = ¿Puedo sincronizar solo algunos productos? = 74 75 Los productos deben tener habilitado "ecommerce" en Perseo para sincronizarse. También puedes filtrar por existencias. 76 77 = ¿Las imágenes se actualizan automáticamente? = 78 79 Sí, las imágenes marcadas como "ecommerce" en Perseo se sincronizan automáticamente, incluyendo la imagen destacada y la galería. 50 80 51 81 == Changelog == 82 83 = 33.0 = 84 * Correcciones con productos inactivos 85 86 = 32.0 = 87 * Correcciones de sincronización de imágenes 88 52 89 = 31.0 = 90 * Correcciones de sincronización de categorías 91 * Recomendación: Eliminar categorías para re-sincronizar 53 92 54 - Correcciones de sincronizacion de categorias 55 - Recomendaciones: Eliminar categorias para que se vuelvan a sincronizar automaticamente. 93 = 30.0 = 94 * Optimización y correcciones varias 56 95 57 = = Changelog ==58 = 30.0 = 96 = 29.0 = 97 * Corrección errores tarifas 59 98 60 - Correcciones de optimización y correcciones varias 99 = 28.0 = 100 * Actualizar campo fecha_sync 61 101 62 = = Changelog ==63 = 29.0 = 102 = 27.0 = 103 * Actualización IVA y parámetros 64 104 65 - Correccion errores tarifas 105 = 26.0 = 106 * Actualización API 66 107 67 = = Changelog ==68 = 28.0 = 108 = 25.0 = 109 * Actualización PC 69 110 70 - Actualizar campo fecha_sync 111 = 24.0 = 112 * Actualización PC 71 113 72 = = Changelog ==73 = 27.0 = 114 = 23.0 = 115 * Actualización precios 74 116 75 - Actualizacion iva y parametros. 76 77 == Changelog == 78 = 26.0 = 79 80 - Actualizacion api. 81 82 == Changelog == 83 = 25.0 = 84 85 - Actualizacion pc. 86 87 == Changelog == 88 = 24.0 = 89 90 - Actualizacion pc. 91 92 == Changelog == 93 = 23.0 = 94 95 - Actualizacion precios . 96 97 == Changelog == 98 = 22.0 = 99 100 - Actualizacion . 101 102 == Changelog == 103 = 21.0 = 104 105 - Actualizacion . 106 107 == Changelog == 108 = 20.0 = 109 110 - Actualizacion . 111 112 == Changelog == 113 = 17.0 = 114 115 - Actualizacion . 116 117 = 16.0 = 118 119 - Actualizacion . 120 121 = 15.0 = 122 123 - Actualizacion . 124 125 = 14.0 = 126 127 - Actualizacion . 128 129 = 13.0 = 130 131 - Actualizacion . 132 133 = 12.0 = 134 135 - Actualizacion . 136 137 = 11.0 = 138 139 - Actualizacion . 140 141 = 10.0 = 142 143 - Actualizacion . 144 145 = 9.0 = 146 147 - Actualizacion . 148 149 = 8.0 = 150 151 - Actualizacion . 152 153 = 7.0 = 154 155 - Actualizacion . 156 157 = 6.0 = 158 159 - Actualizacion . 160 161 = 5.0 = 162 163 - Actualizacion de correo. 164 165 = 5.0 = 166 167 - Actualizacion de imagenes. 168 169 = 4.0 = 170 171 - Actualizacion de stock. 172 173 = 3.0 = 174 175 - A change since the previous version. 176 177 = 2.0 = 178 179 - A change since the previous version. 180 - Fixed a pagination bug. 181 182 = 1.1 = 183 184 - A change since the previous version. 185 - Fixed a pagination bug. 186 187 = 1.0 = 188 189 - New: Basic functionalities for this plugin. 190 191 == Upgrade Notice == 192 193 = 1.1 = 194 Actualizacion de imagenes 117 = 22.0 - 1.0 = 118 * Versiones anteriores con mejoras incrementales -
perseo-software/trunk/includes/PluginPerseo_cron.php
r3270560 r3439783 2 2 class CPerseo_Cron 3 3 { 4 private $tarifas_cambiaron = false; // 🔹Variable para detectar cambios en tarifas4 private $tarifas_cambiaron = false; // Variable para detectar cambios en tarifas 5 5 6 6 private function ejecutar_proceso_con_bloqueo($proceso, $callback) … … 32 32 public function fperseo_inicializador() 33 33 { 34 //elimina el cron35 34 $perseo_parametros = get_option('pluginperseo_parametros'); 36 35 37 // echo "-".$perseo_parametros['perseosincronizar']; 38 //echo "<br>"; 36 // 🔹 Validar que sea array 37 if (!is_array($perseo_parametros)) { 38 $perseo_parametros = []; 39 } 40 39 41 if (isset($perseo_parametros['perseosincronizar'])) { 40 41 42 if ($perseo_parametros['perseosincronizar'] == "") { 42 43 43 $perseo_timestamp = wp_next_scheduled('intervalo_perseo'); 44 wp_unschedule_event($perseo_timestamp, 'intervalo_perseo', 'perseo_cron'); 45 wp_clear_scheduled_hook('intervalo_perseo', 'perseo_cron'); 46 //wp_unschedule_event(time(), 'intervalo_perseo'); 47 }; 48 //crea el cron 49 if (!wp_next_scheduled('perseo_cron')) { 44 if ($perseo_timestamp) { 45 wp_unschedule_event($perseo_timestamp, 'intervalo_perseo'); 46 } 47 wp_clear_scheduled_hook('intervalo_perseo'); // 🔹 Sin segundo argumento 48 } 49 50 if (!wp_next_scheduled('perseo_cron') && !empty($perseo_parametros['perseosincronizar'])) { 50 51 wp_schedule_event(time() + (intval($perseo_parametros['perseosincronizar']) * 60), 'intervalo_perseo', 'perseo_cron'); 51 } ;52 } ;52 } 53 } 53 54 } 54 55 55 56 public function fperseo_intervalos($perseo_intervalos) 56 57 { 57 //sincronizar58 58 $perseo_parametros = get_option('pluginperseo_parametros'); 59 if (isset($perseo_parametros['perseosincronizar'])) { 60 if (empty($perseo_parametros['perseosincronizar'])) { 61 //$perseo_valorCron=intval(1)*60; 62 } else { 63 $perseo_valorCron = intval($perseo_parametros['perseosincronizar']) * 60; 64 }; 65 66 $perseo_intervalos['intervalo_perseo'] = [ 67 'interval' => $perseo_valorCron, 68 'display' => 'Cada tiempo ' . $perseo_parametros['perseosincronizar'] . ' Perseo' 69 ]; 70 71 return $perseo_intervalos; 72 }; 59 60 // 🔹 Validar que sea array 61 if (!is_array($perseo_parametros)) { 62 $perseo_parametros = []; 63 } 64 65 if (isset($perseo_parametros['perseosincronizar']) && !empty($perseo_parametros['perseosincronizar'])) { 66 $perseo_valorCron = intval($perseo_parametros['perseosincronizar']) * 60; 67 68 // 🔹 Evitar división por cero 69 if ($perseo_valorCron > 0) { 70 $perseo_intervalos['intervalo_perseo'] = [ 71 'interval' => $perseo_valorCron, 72 'display' => 'Cada ' . $perseo_parametros['perseosincronizar'] . ' minutos Perseo' 73 ]; 74 } 75 } 76 77 return $perseo_intervalos; 73 78 } 74 79 … … 84 89 error_log("[" . date('Y-m-d H:i:s') . "] Cambio detectado en tarifas. Forzando actualización de productos."); 85 90 86 // 🔹Marcar que las tarifas cambiaron91 // Marcar que las tarifas cambiaron 87 92 $this->tarifas_cambiaron = true; 88 93 89 // 🔹Actualizar la fecha de modificación de todos los productos a una fecha menor94 // Actualizar la fecha de modificación de todos los productos a una fecha menor 90 95 $fecha_antigua = date('Y-m-d H:i:s', strtotime('-1 day')); 91 96 $wpdb->query("UPDATE {$table_prefix}posts p … … 270 275 } 271 276 272 // 🔹Obtener pedidos pendientes de enviar a Perseo (Optimizado con LIMIT 50)277 // Obtener pedidos pendientes de enviar a Perseo (Optimizado con LIMIT 50) 273 278 $query_pedidos = " 274 279 SELECT p.ID as codigoPedido, p.post_date, p.post_status, u.ID as user_id, u.user_login, c.* … … 294 299 $perseo_DetallePedido = []; 295 300 296 // 🔹Obtener detalles del pedido (Optimizado con JOIN)301 // Obtener detalles del pedido (Optimizado con JOIN) 297 302 $query_detalles = $wpdb->prepare(" 298 303 SELECT … … 312 317 foreach ($detalles as $detalle) { 313 318 $perseo_CodProdP = isset($detalle->attributes) ? unserialize($detalle->attributes) : []; 314 $perseo_CodProdP = array_change_key_case($perseo_CodProdP, CASE_LOWER); // 🔹Convierte todas las claves a minúsculas319 $perseo_CodProdP = array_change_key_case($perseo_CodProdP, CASE_LOWER); // Convierte todas las claves a minúsculas 315 320 $perseo_DatoIva = isset($detalle->iva) ? floatval($detalle->iva) : 0; 316 321 $perseo_precio = isset($detalle->price) ? floatval($detalle->price) : 0; … … 348 353 $totales = $this->calcularTotales($productos); 349 354 350 // 🔹Obtener método de pago (Evita errores con IFNULL)355 // Obtener método de pago (Evita errores con IFNULL) 351 356 $perseo_TipoMetodoPago = $wpdb->get_var($wpdb->prepare(" 352 357 SELECT IFNULL(meta_value, 'Desconocido') … … 356 361 ", $pedido->codigoPedido)); 357 362 358 // 🔹Armar cabecera del pedido363 // Armar cabecera del pedido 359 364 $perseo_CabeceraPedidos = [ 360 365 'pedidos' => [ … … 394 399 } 395 400 396 // 🔹Enviar pedidos a Perseo401 // Enviar pedidos a Perseo 397 402 $this->enviar_pedido_a_perseo($perseo_registroPedido, $perseo_config); 398 403 }); … … 406 411 } 407 412 408 // 🔹Construcción de la API URL de Perseo413 // Construcción de la API URL de Perseo 409 414 $perseo_urlpedido = ($perseo_config['perseotiposoftware'] === 'WEB') 410 415 ? $perseo_config['perseoservidor'] . '/api/pedidos_crear' 411 416 : $perseo_config['perseocertificado'] . '://' . $perseo_config['perseoip'] . '/api/pedidos_crear'; 412 417 413 // 🔹Cuerpo de la solicitud418 // Cuerpo de la solicitud 414 419 $perseo_InsertarPedido = [ 415 420 'api_key' => $perseo_config['perseotoken'], … … 418 423 $perseo_bodypedido = wp_json_encode($perseo_InsertarPedido); 419 424 420 // 🔹Enviar a la API de Perseo425 // Enviar a la API de Perseo 421 426 $response = wp_remote_post( 422 427 $perseo_urlpedido, … … 429 434 ); 430 435 431 // 🔹Manejo de errores en la API436 // Manejo de errores en la API 432 437 if (is_wp_error($response)) { 433 438 error_log("[" . date('Y-m-d H:i:s') . "] Error en la conexión con Perseo: " . $response->get_error_message()); … … 443 448 } 444 449 445 // 🔹Marcar pedidos como completados en WooCommerce si fueron aceptados por Perseo450 // Marcar pedidos como completados en WooCommerce si fueron aceptados por Perseo 446 451 global $wpdb, $table_prefix; 447 // 🔹Actualizar pedidos en WordPress marcándolos como "EnviadoPerseo"452 // Actualizar pedidos en WordPress marcándolos como "EnviadoPerseo" 448 453 foreach ($perseo_registroPedido as $pedido) { 449 454 if (!empty($pedido['pedidos']['pedido_wp_id']) && intval($pedido['pedidos']['pedido_wp_id']) > 0) { … … 499 504 $totalProducto = $subtotalConDescuento + $ivaMonto; 500 505 501 // 🔹Acumular valores en los totales506 // Acumular valores en los totales 502 507 $totales['subtotal'] += $subtotalProducto; 503 508 $totales['descuentoTotal'] += $descuentoMonto; 504 509 505 // 🔹Diferenciar por tipo de IVA510 // Diferenciar por tipo de IVA 506 511 if ($valoriva > 0) { 507 512 if ($valoriva === 0.05) { … … 519 524 } 520 525 521 // 🔹Acumulación de totales generales526 // Acumulación de totales generales 522 527 $totales['total'] += $totalProducto; 523 528 $totales['totalItems'] += 1; // Contar cada línea de producto … … 525 530 } 526 531 527 // 🔹Calcular subtotal neto total532 // Calcular subtotal neto total 528 533 $totales['subtotalNeto'] = $totales['subtotalNetoConIva'] + $totales['subtotalNetoIva5'] + $totales['subtotalNetoSinIva']; 529 534 530 // 🔹Aplicar `number_format()` solo al final para evitar errores de precisión535 // Aplicar `number_format()` solo al final para evitar errores de precisión 531 536 foreach ($totales as $key => $value) { 532 537 $totales[$key] = number_format(round($value, 3), 3, '.', ''); … … 594 599 } 595 600 596 // 🔹Obtener todos los identificaciones de clientes existentes en una sola consulta601 // Obtener todos los identificaciones de clientes existentes en una sola consulta 597 602 $clientes_existentes = $wpdb->get_col( 598 603 "SELECT meta_value FROM {$table_prefix}usermeta WHERE meta_key = 'PerseoIdentificacion'" 599 604 ); 600 605 601 // 🔹Convertir el array a un conjunto (más eficiente en búsquedas)606 // Convertir el array a un conjunto (más eficiente en búsquedas) 602 607 $clientes_existentes = array_flip($clientes_existentes); 603 608 604 // 🔹Procesar los clientes recibidos de la API609 // Procesar los clientes recibidos de la API 605 610 $clientes_nuevos = []; 606 611 … … 619 624 } 620 625 621 // 🔹Construir los datos para la inserción masiva626 // Construir los datos para la inserción masiva 622 627 $nombre_array = explode(' ', $razonsocial); 623 628 $first_name = sanitize_text_field($nombre_array[0] ?? ''); … … 640 645 } 641 646 642 // 🔹Insertar clientes nuevos647 // Insertar clientes nuevos 643 648 foreach ($clientes_nuevos as $cliente) { 644 649 $user_id = wp_insert_user($cliente); … … 655 660 }); 656 661 } 657 658 /**659 * Enviar email de bienvenida al cliente660 */661 // private function enviar_email_bienvenida($userdata)662 // {663 // $site_url = home_url();664 // $headers = ['Content-Type: text/html; charset=UTF-8'];665 // $subject = "Bienvenido a nuestra plataforma E-Commerce";666 // $message = "667 // <h1>Bienvenido, {$userdata['user_login']}!</h1>668 // <p>Gracias por unirte a nuestra plataforma E-Commerce.</p>669 // <p><strong>Usuario:</strong> {$userdata['user_login']}</p>670 // <p><strong>Contraseña:</strong> {$userdata['user_pass']}</p>671 // <p>Visita nuestra página aquí: <a href='{$site_url}'>{$site_url}</a></p>672 // <p>Atentamente,</p>673 // <p>El equipo de E-Commerce</p>";674 675 // wp_mail($userdata['user_email'], $subject, $message, $headers);676 // }677 662 678 663 public function fperseo_categoria() … … 807 792 } 808 793 809 // 🔹Construir URL de la API794 // Construir URL de la API 810 795 $perseo_urliva = ($perseo_config['perseotiposoftware'] === 'WEB') 811 796 ? $perseo_config['perseoservidor'] . '/api/tipoiva_consulta' 812 797 : $perseo_config['perseocertificado'] . '://' . $perseo_config['perseoip'] . '/api/tipoiva_consulta'; 813 798 814 // 🔹Consultar API de impuestos799 // Consultar API de impuestos 815 800 $perseo_responseiva = wp_remote_post( 816 801 $perseo_urliva, … … 843 828 } 844 829 845 // 🔹Obtener todas las clases de impuesto existentes en WooCommerce830 // Obtener todas las clases de impuesto existentes en WooCommerce 846 831 $clases_existentes = $wpdb->get_results( 847 832 "SELECT slug FROM {$table_prefix}wc_tax_rate_classes", … … 850 835 $clases_existentes_slugs = array_column($clases_existentes, 'slug'); 851 836 852 // 🔹Obtener todas las tasas de impuestos ya existentes en WooCommerce837 // Obtener todas las tasas de impuestos ya existentes en WooCommerce 853 838 $ivas_existentes = $wpdb->get_results( 854 839 "SELECT tax_rate_id, tax_rate, tax_rate_class FROM {$table_prefix}woocommerce_tax_rates", … … 856 841 ); 857 842 858 // 🔹Procesar los impuestos recibidos843 // Procesar los impuestos recibidos 859 844 foreach ($perseo_datosivas['iva'] as $datoiva) { 860 845 $valor_iva = sanitize_text_field($datoiva['valor']); 861 846 $nombre_iva = sanitize_text_field($datoiva['porcentaje']); 862 847 863 // 🔹Identificar las clases de impuestos especiales848 // Identificar las clases de impuestos especiales 864 849 if (strpos(strtolower($nombre_iva), 'no objeto') !== false) { 865 850 $tax_rate_class = "iva-no-objeto"; … … 873 858 } 874 859 875 // 🔹Verificar si la clase de impuesto ya existe en wp_wc_tax_rate_classes860 // Verificar si la clase de impuesto ya existe en wp_wc_tax_rate_classes 876 861 if (!in_array($tax_rate_class, $clases_existentes_slugs)) { 877 862 $wpdb->insert( … … 883 868 } 884 869 885 // 🔹Verificar si el impuesto ya existe en woocommerce_tax_rates870 // Verificar si el impuesto ya existe en woocommerce_tax_rates 886 871 $iva_existente = null; 887 872 foreach ($ivas_existentes as $iva) { … … 893 878 894 879 if (!$iva_existente) { 895 // 🔹Insertar nueva tasa de impuesto880 // Insertar nueva tasa de impuesto 896 881 $wpdb->insert( 897 882 "{$table_prefix}woocommerce_tax_rates", … … 960 945 } 961 946 962 // 🔹Obtener todos los productos existentes y sus fechas de modificación en una sola consulta947 // Obtener todos los productos existentes y sus fechas de modificación en una sola consulta 963 948 $productos_existentes = $wpdb->get_results( 964 949 "SELECT p.ID AS post_id, pm.meta_value AS perseo_id, p.post_modified … … 969 954 ); 970 955 971 // 🔹Convertir el array a un conjunto para búsqueda rápida956 // Convertir el array a un conjunto para búsqueda rápida 972 957 $productos_existentes_map = []; 973 958 $productos_fechas = []; … … 977 962 } 978 963 979 // 🔹Listas para productos nuevos y actualizados964 // Listas para productos nuevos y actualizados 980 965 $productos_nuevos = []; 981 966 $productos_actualizados = []; … … 985 970 if ($producto['existenciastotales'] >= $perseo_parametros['perseoexistencias']) { 986 971 if (isset($productos_existentes_map[$producto['productosid']])) { 987 // 🔹Obtener la fecha de sincronización del producto en la API972 // Obtener la fecha de sincronización del producto en la API 988 973 $fecha_sync = date_format(date_create($producto['fecha_sync']), 'Y-m-d H:i:s'); 989 974 $fecha_wp = $productos_fechas[$producto['productosid']]; 990 975 991 // 🔹Forzar actualización si las tarifas han cambiado o si `fecha_sync` es más reciente976 // Forzar actualización si las tarifas han cambiado o si `fecha_sync` es más reciente 992 977 if ($this->tarifas_cambiaron || $fecha_sync > $fecha_wp) { 993 978 $productos_actualizados[] = [ … … 1003 988 } 1004 989 1005 // 🔹Procesar productos nuevos990 // Procesar productos nuevos 1006 991 if (!empty($productos_nuevos)) { 1007 992 foreach ($productos_nuevos as $producto) { … … 1011 996 } 1012 997 1013 // 🔹Procesar productos actualizados998 // Procesar productos actualizados 1014 999 if (!empty($productos_actualizados)) { 1015 1000 foreach ($productos_actualizados as $item) { … … 1018 1003 error_log("[" . date('Y-m-d H:i:s') . "] Se han actualizado " . count($productos_actualizados) . " productos."); 1019 1004 } 1005 1006 $this->desactivar_productos_inactivos($wpdb, $table_prefix, $perseo_config); 1007 1020 1008 } 1021 1009 }); 1022 // 🔹Resetear la variable de control después de la ejecución1010 // Resetear la variable de control después de la ejecución 1023 1011 $this->tarifas_cambiaron = false; 1012 } 1013 1014 private function desactivar_productos_inactivos($wpdb, $table_prefix, $perseo_config) 1015 { 1016 error_log("[" . date('Y-m-d H:i:s') . "] Iniciando proceso de desactivación de productos inactivos."); 1017 1018 // Construir URL para consulta de productos inactivos 1019 $perseo_url_inactivos = ($perseo_config['perseotiposoftware'] === 'WEB') 1020 ? $perseo_config['perseoservidor'] . '/api/productos_consulta_movil' 1021 : $perseo_config['perseocertificado'] . '://' . $perseo_config['perseoip'] . '/api/productos_consulta_movil'; 1022 1023 $productos_inactivos = []; 1024 1025 // Primera consulta: productos con estado = 0 1026 $body_estado = [ 1027 'api_key' => $perseo_config['perseotoken'], 1028 'estado' => '0' 1029 ]; 1030 1031 $response_estado = wp_remote_post($perseo_url_inactivos, [ 1032 'method' => 'POST', 1033 'timeout' => 1800, 1034 'headers' => ['Content-Type' => 'application/json'], 1035 'body' => wp_json_encode($body_estado) 1036 ]); 1037 1038 if (!is_wp_error($response_estado) && !empty($response_estado['body'])) { 1039 $productos_estado_0 = json_decode(wp_remote_retrieve_body($response_estado), true)['productos'] ?? []; 1040 $productos_inactivos = array_merge($productos_inactivos, $productos_estado_0); 1041 error_log("[" . date('Y-m-d H:i:s') . "] Productos con estado=0 obtenidos: " . count($productos_estado_0)); 1042 } else { 1043 error_log("[" . date('Y-m-d H:i:s') . "] Error al obtener productos con estado=0 de Perseo."); 1044 } 1045 1046 // Segunda consulta: productos con ecommerce_estado = 2 1047 $body_ecommerce = [ 1048 'api_key' => $perseo_config['perseotoken'], 1049 'ecommerce_estado' => '2' 1050 ]; 1051 1052 $response_ecommerce = wp_remote_post($perseo_url_inactivos, [ 1053 'method' => 'POST', 1054 'timeout' => 1800, 1055 'headers' => ['Content-Type' => 'application/json'], 1056 'body' => wp_json_encode($body_ecommerce) 1057 ]); 1058 1059 if (!is_wp_error($response_ecommerce) && !empty($response_ecommerce['body'])) { 1060 $productos_ecommerce_2 = json_decode(wp_remote_retrieve_body($response_ecommerce), true)['productos'] ?? []; 1061 $productos_inactivos = array_merge($productos_inactivos, $productos_ecommerce_2); 1062 error_log("[" . date('Y-m-d H:i:s') . "] Productos con ecommerce_estado=2 obtenidos: " . count($productos_ecommerce_2)); 1063 } else { 1064 error_log("[" . date('Y-m-d H:i:s') . "] Error al obtener productos con ecommerce_estado=2 de Perseo."); 1065 } 1066 1067 error_log("[" . date('Y-m-d H:i:s') . "] Total productos inactivos obtenidos de API: " . count($productos_inactivos)); 1068 1069 if (empty($productos_inactivos)) { 1070 error_log("[" . date('Y-m-d H:i:s') . "] No hay productos inactivos en Perseo."); 1071 return; 1072 } 1073 1074 // Obtener IDs únicos de productos inactivos de Perseo (evitar duplicados) 1075 $perseo_ids_inactivos = array_unique(array_column($productos_inactivos, 'productosid')); 1076 1077 if (empty($perseo_ids_inactivos)) { 1078 error_log("[" . date('Y-m-d H:i:s') . "] No se encontraron IDs de productos inactivos."); 1079 return; 1080 } 1081 1082 // Preparar placeholders para la consulta IN 1083 $placeholders = implode(',', array_fill(0, count($perseo_ids_inactivos), '%s')); 1084 1085 // Obtener posts de WordPress que tienen esos PERSEOID y están publicados 1086 $query = $wpdb->prepare( 1087 "SELECT p.ID, pm.meta_value AS perseo_id 1088 FROM {$table_prefix}posts p 1089 INNER JOIN {$table_prefix}postmeta pm ON p.ID = pm.post_id 1090 WHERE pm.meta_key = 'PERSEOID' 1091 AND pm.meta_value IN ($placeholders) 1092 AND p.post_status = 'publish'", 1093 ...$perseo_ids_inactivos 1094 ); 1095 1096 $productos_a_desactivar = $wpdb->get_results($query); 1097 1098 if (empty($productos_a_desactivar)) { 1099 error_log("[" . date('Y-m-d H:i:s') . "] No hay productos en WordPress que requieran desactivación."); 1100 return; 1101 } 1102 1103 error_log("[" . date('Y-m-d H:i:s') . "] Productos a desactivar en WordPress: " . count($productos_a_desactivar)); 1104 1105 $ids_desactivar = array_column($productos_a_desactivar, 'ID'); 1106 1107 // Log de IDs que serán desactivados 1108 error_log("[" . date('Y-m-d H:i:s') . "] IDs de productos a desactivar: " . implode(', ', $ids_desactivar)); 1109 1110 $desactivados = 0; 1111 1112 foreach ($ids_desactivar as $post_id) { 1113 // Cambiar el estado del producto a 'draft' para que no aparezca en la tienda 1114 $resultado = $wpdb->update( 1115 "{$table_prefix}posts", 1116 [ 1117 'post_status' => 'draft', 1118 'post_modified' => current_time('mysql'), 1119 'post_modified_gmt' => current_time('mysql', true) 1120 ], 1121 ['ID' => $post_id] 1122 ); 1123 1124 if ($resultado !== false) { 1125 $desactivados++; 1126 error_log("[" . date('Y-m-d H:i:s') . "] Producto #{$post_id} desactivado correctamente (cambiado a draft)."); 1127 } else { 1128 error_log("[" . date('Y-m-d H:i:s') . "] Error al desactivar producto #{$post_id}."); 1129 } 1130 } 1131 1132 // Limpiar caché de WooCommerce 1133 wc_delete_product_transients(); 1134 1135 error_log("[" . date('Y-m-d H:i:s') . "] Proceso completado: Se han desactivado {$desactivados} productos."); 1024 1136 } 1025 1137 … … 1061 1173 $fecha_sync = date_format(date_create($producto['fecha_sync']), 'Y-m-d H:i:s'); 1062 1174 1063 // 🔹Realizar la actualización en un solo paso1175 // Realizar la actualización en un solo paso 1064 1176 $wpdb->update("{$table_prefix}posts", [ 1065 1177 'post_content' => $producto['fichatecnica'], 1066 1178 'post_title' => $producto['descripcion'], 1067 1179 'post_excerpt' => $producto['descripcion'], 1180 'post_status' => 'publish', 1068 1181 'post_modified' => $fecha_sync, 1069 1182 'post_modified_gmt' => '0000-00-00 00:00:00' 1070 1183 ], ['ID' => $idPost]); 1071 1184 1072 // 🔹Usar una sola consulta para actualizar metadatos relevantes1185 // Usar una sola consulta para actualizar metadatos relevantes 1073 1186 $metadatos = [ 1074 1187 '_stock' => $producto['existenciastotales'], … … 1093 1206 } 1094 1207 1095 // 🔹Agregar la clase de impuesto según el porcentaje de IVA del producto1208 // Agregar la clase de impuesto según el porcentaje de IVA del producto 1096 1209 $tax_class = ($producto['porcentajeiva'] == 0) ? 'tasa-cero' : "iva-{$producto['porcentajeiva']}"; 1097 1210 $metadatos['_tax_class'] = $tax_class; 1098 1211 $metadatos['_tax_status'] = 'taxable'; // Asegurar que el producto usa impuestos 1099 1212 1100 // 🔹Actualizar todos los metadatos en una sola ejecución1213 // Actualizar todos los metadatos en una sola ejecución 1101 1214 foreach ($metadatos as $key => $value) { 1102 1215 update_post_meta($idPost, $key, $value); 1103 1216 } 1104 1217 1105 // 🔹Actualizar categorías solo si es necesario1218 // Actualizar categorías solo si es necesario 1106 1219 $this->actualizar_categorias_producto($producto, $idPost, $wpdb, $table_prefix, $perseo_parametros); 1107 1220 1108 1221 if ($this->tarifas_cambiaron == false) { 1109 // 🔹Procesar imágenes solo si es necesario1222 // Procesar imágenes solo si es necesario 1110 1223 if ($perseo_parametros['perseoimagenes'] === 'SI') { 1111 1224 $this->procesar_imagenes_producto($producto['productosid'], $idPost, $wpdb, $table_prefix, $perseo_urlimagen, $perseo_config); … … 1130 1243 ]; 1131 1244 1132 // 🔹Procesar tarifas1245 // Procesar tarifas 1133 1246 $tarifas = $producto['tarifas'] ?? []; 1134 1247 $tarifa_venta = 0; … … 1147 1260 } 1148 1261 1149 // 🔹Insertar metadatos en una sola consulta (batch insert)1262 // Insertar metadatos en una sola consulta (batch insert) 1150 1263 $values = []; 1151 1264 foreach ($metadatos as $meta) { … … 1155 1268 $wpdb->query($query); 1156 1269 1157 // 🔹Atributos personalizados (serializados)1270 // Atributos personalizados (serializados) 1158 1271 $attributes = serialize([ 1159 1272 'ID_Perseo' => ['name' => 'ID_Perseo', 'value' => $producto['productosid'], 'is_visible' => '0'], … … 1166 1279 ]); 1167 1280 1168 // 🔹Tabla de búsqueda rápida `wc_product_meta_lookup`1281 // Tabla de búsqueda rápida `wc_product_meta_lookup` 1169 1282 $wpdb->insert("{$table_prefix}wc_product_meta_lookup", [ 1170 1283 'product_id' => $idPost, … … 1187 1300 private function actualizar_categorias_producto($producto, $idPost, $wpdb, $table_prefix, $perseo_parametros) 1188 1301 { 1189 // 🔹Determinar la clave de categoría según los parámetros de configuración1302 // Determinar la clave de categoría según los parámetros de configuración 1190 1303 $categoria_clave = null; 1191 1304 // Mapeo de valores … … 1214 1327 } 1215 1328 1216 // 🔹Obtener todas las categorías existentes en una sola consulta1329 // Obtener todas las categorías existentes en una sola consulta 1217 1330 static $categorias_map = null; 1218 1331 if ($categorias_map === null) { … … 1223 1336 } 1224 1337 1225 // 🔹Buscar la categoría en el mapa precargado1338 // Buscar la categoría en el mapa precargado 1226 1339 $resProdCat = null; 1227 1340 foreach ($categorias_map as $categoria) { … … 1237 1350 } 1238 1351 1239 // 🔹Eliminar relaciones existentes1352 // Eliminar relaciones existentes 1240 1353 $wpdb->delete("{$table_prefix}term_relationships", ['object_id' => $idPost]); 1241 1354 1242 // 🔹Insertar nueva relación1355 // Insertar nueva relación 1243 1356 $wpdb->insert("{$table_prefix}term_relationships", [ 1244 1357 'object_id' => $idPost, … … 1250 1363 private function procesar_imagenes_producto($productoID, $idPost, $wpdb, $table_prefix, $perseo_urlimagen, $perseo_config) 1251 1364 { 1252 // 🔹Limpiar cache para evitar inconsistencias al agregar nuevas imágenes1365 // Limpiar cache para evitar inconsistencias al agregar nuevas imágenes 1253 1366 static $imagenes_cache = []; 1254 1367 // Forzar la actualización del cache para este producto específico 1255 1368 unset($imagenes_cache[$productoID]); 1256 1369 1257 // 🔹Obtener imágenes del producto desde la API en una sola llamada1370 // Obtener imágenes del producto desde la API en una sola llamada 1258 1371 if (!isset($imagenes_cache[$productoID])) { 1259 1372 $body = ['api_key' => $perseo_config['perseotoken'], 'productosid' => $productoID]; … … 1282 1395 } 1283 1396 1284 // 🔹Obtener imágenes ya asociadas al producto1397 // Obtener imágenes ya asociadas al producto 1285 1398 $imagenes_existentes = $wpdb->get_results($wpdb->prepare( 1286 1399 "SELECT ID, guid, post_title FROM {$table_prefix}posts WHERE post_parent = %d AND post_type = 'attachment'", … … 1292 1405 wp_mkdir_p($base_upload_path); // Crear el directorio si no existe 1293 1406 1294 // 🔹Lista para seguimiento de imágenes procesadas1407 // Lista para seguimiento de imágenes procesadas 1295 1408 $imagenes_procesadas = []; 1296 1409 $thumbnail_id = null; … … 1323 1436 } 1324 1437 1325 // 🔹Guardar imagen en el sistema de archivos (siempre, para actualizar contenido)1438 // Guardar imagen en el sistema de archivos (siempre, para actualizar contenido) 1326 1439 $image_data = base64_decode(preg_replace('#^data:image/\w+;base64,#i', '', $imagen['imagen'])); 1327 1440 if (file_put_contents($file_path, $image_data) === false) { … … 1341 1454 wp_update_attachment_metadata($attachment_id, $attachment_metadata); 1342 1455 } else { 1343 // 🔹Insertar la imagen como nuevo adjunto en WordPress1456 // Insertar la imagen como nuevo adjunto en WordPress 1344 1457 $attachment = [ 1345 1458 'post_mime_type' => 'image/png', … … 1357 1470 } 1358 1471 1359 // 🔹Generar metadatos de la imagen1472 // Generar metadatos de la imagen 1360 1473 require_once ABSPATH . 'wp-admin/includes/image.php'; 1361 1474 $attachment_metadata = wp_generate_attachment_metadata($attachment_id, $file_path); … … 1366 1479 $imagenes_procesadas[] = $attachment_id; 1367 1480 1368 // 🔹Asignar como imagen destacada o añadir a la galería1481 // Asignar como imagen destacada o añadir a la galería 1369 1482 if ($imagen['primera'] == 1) { 1370 1483 $thumbnail_id = $attachment_id; // Guardar como imagen destacada … … 1381 1494 } 1382 1495 1383 // 🔹Eliminar imágenes antiguas que ya no existen en la API1496 // Eliminar imágenes antiguas que ya no existen en la API 1384 1497 foreach ($imagenes_existentes as $id => $img) { 1385 1498 if (!in_array($id, $imagenes_procesadas)) { … … 1392 1505 error_log("Producto {$productoID}: Procesadas " . count($imagenes_procesadas) . " imágenes, " . count($gallery_ids) . " en galería"); 1393 1506 1394 // 🔹Asignar imagen destacada al producto1507 // Asignar imagen destacada al producto 1395 1508 if ($thumbnail_id) { 1396 1509 update_post_meta($idPost, '_thumbnail_id', $thumbnail_id); 1397 1510 } 1398 1511 1399 // 🔹Asignar galería de imágenes al producto (siempre actualizar toda la galería)1512 // Asignar galería de imágenes al producto (siempre actualizar toda la galería) 1400 1513 if (!empty($gallery_ids)) { 1401 1514 update_post_meta($idPost, '_product_image_gallery', implode(',', $gallery_ids));
Note: See TracChangeset
for help on using the changeset viewer.