Changeset 3581159
- Timestamp:
- 06/22/2026 04:28:47 AM (4 months ago)
- Location:
- pfacturas-for-woocommerce
- Files:
-
- 12 edited
- 1 copied
-
tags/1.3.0.1 (copied) (copied from pfacturas-for-woocommerce/trunk )
-
tags/1.3.0.1/assets/blocks.js (modified) (1 diff)
-
tags/1.3.0.1/includes/class-pf-checkout.php (modified) (1 diff)
-
tags/1.3.0.1/includes/class-pf-emitter.php (modified) (1 diff)
-
tags/1.3.0.1/includes/class-pf-mapper.php (modified) (1 diff)
-
tags/1.3.0.1/pFacturas.php (modified) (2 diffs)
-
tags/1.3.0.1/readme.txt (modified) (2 diffs)
-
trunk/assets/blocks.js (modified) (1 diff)
-
trunk/includes/class-pf-checkout.php (modified) (1 diff)
-
trunk/includes/class-pf-emitter.php (modified) (1 diff)
-
trunk/includes/class-pf-mapper.php (modified) (1 diff)
-
trunk/pFacturas.php (modified) (2 diffs)
-
trunk/readme.txt (modified) (2 diffs)
Legend:
- Unmodified
- Added
- Removed
-
pfacturas-for-woocommerce/tags/1.3.0.1/assets/blocks.js
r3562658 r3581159 418 418 var intlEl=document.getElementById('pf_intl'); if(intlEl) intlEl.style.display='block'; 419 419 var required = tot > umbral; 420 // Cuando required=true: forzar declare='1' en el select oculto antes de leer su valor. 421 // Si no, el form envía el "0" default y el backend trata la orden como consumo final. 422 if (required) { 423 var declareSelEl = document.getElementById('pf_intl_declare'); 424 if (declareSelEl && declareSelEl.value !== '1') { declareSelEl.value = '1'; } 425 } 420 426 var declareYes = (document.getElementById('pf_intl_declare')||{}).value === '1'; 421 427 var sectionShown = required || declareYes; -
pfacturas-for-woocommerce/tags/1.3.0.1/includes/class-pf-checkout.php
r3562658 r3581159 540 540 $script .= ' if(required){ declareField.style.setProperty("display","none","important"); }' . "\n"; 541 541 $script .= ' else { declareField.style.removeProperty("display"); }' . "\n"; 542 $script .= ' }' . "\n"; 543 $script .= ' // Cuando required=true: el select declare está oculto pero el form igual lo envía.' . "\n"; 544 $script .= ' // Forzar value="1" para que el backend reciba la declaración correctamente (no quede el "0" default).' . "\n"; 545 $script .= ' if(required){' . "\n"; 546 $script .= ' var declareSelect = by("_pf_intl_declare");' . "\n"; 547 $script .= ' if(declareSelect && declareSelect.value !== "1"){ declareSelect.value = "1"; }' . "\n"; 542 548 $script .= ' }' . "\n"; 543 549 $script .= ' // Etiqueta required visible solo si supera umbral.' . "\n"; -
pfacturas-for-woocommerce/tags/1.3.0.1/includes/class-pf-emitter.php
r3560071 r3581159 1010 1010 $rut_flag = get_post_meta($order_id, '_pf_rut_flag', true); 1011 1011 1012 // Modo "Cualquier País" (Feature 1.3.0.0): los datos fiscales viven en metas _pf_intl_* en lugar de 1013 // los _pf_*_pf clásicos del modo UY. Validamos con la lógica intl y salimos. 1014 if (($settings['checkout_country_mode'] ?? 'UY') === 'ANY') { 1015 $intl_declare = (string) get_post_meta($order_id, '_pf_intl_declare', true); 1016 $intl_tipo = (string) get_post_meta($order_id, '_pf_intl_tipo_doc', true); 1017 $intl_doc = (string) get_post_meta($order_id, '_pf_intl_doc', true); 1018 $intl_razon = (string) get_post_meta($order_id, '_pf_intl_razon', true); 1019 1020 // Failsafe paralelo al del mapper: si hay tipo+doc llenos, asumir declarado aunque declare!='1'. 1021 $intl_has_data = ($intl_tipo !== '' && trim($intl_doc) !== ''); 1022 $intl_declared = ($intl_declare === '1') || $intl_has_data; 1023 1024 $total = abs((float)$order->get_total()); 1025 $moneda = $order->get_currency(); 1026 $umbral_ui = (float)($settings['umbral_ident'] ?? 0); 1027 $umbral = ($umbral_ui > 0) ? pfwc_calcular_umbral_en_moneda($umbral_ui, $moneda, $settings) : 0; 1028 $supera_umbral = ($umbral > 0 && $total > $umbral); 1029 1030 // Si supera umbral y no se declaró nada, bloquear. 1031 if ($supera_umbral && !$intl_declared) { 1032 return 'El monto ($' . number_format($total, 2) . ') supera el umbral de identificación ($' . number_format($umbral, 2) . '). Debe completar Tipo de Documento y Documento.'; 1033 } 1034 // Si se declaró pero faltan datos, bloquear. 1035 if ($intl_declared) { 1036 if ($intl_tipo === '') return 'Falta el Tipo de Documento para identificar al receptor del CFE.'; 1037 if (trim($intl_doc) === '') return 'Falta el Documento para identificar al receptor del CFE.'; 1038 // Tipos 1 (NIE) y 2 (RUT) → validar DV con algoritmo RUT. 1039 if (($intl_tipo === '1' || $intl_tipo === '2') && !pfwc_validar_rut($intl_doc)) { 1040 return 'El Documento "' . $intl_doc . '" no es válido. Verifique el dígito verificador.'; 1041 } 1042 // Tipo 3 (CI uruguaya) → validar DV con algoritmo CI. 1043 if ($intl_tipo === '3' && !pfwc_validar_ci($intl_doc)) { 1044 return 'La Cédula de Identidad ' . $intl_doc . ' no es válida. Verifique el dígito verificador.'; 1045 } 1046 // Tipos 1, 2, 7 (empresas): Denominación Social obligatoria. 1047 if (in_array($intl_tipo, ['1','2','7'], true) && trim($intl_razon) === '') { 1048 return 'Falta la Denominación Social para emitir el CFE de empresa.'; 1049 } 1050 } 1051 return null; // OK 1052 } 1053 1012 1054 // Heurística: si la detección previa marcó error (ej: RUT inválido + razón social con 1013 1055 // sufijo empresarial), bloquear emisión con el mensaje persistido. -
pfacturas-for-woocommerce/tags/1.3.0.1/includes/class-pf-mapper.php
r3562658 r3581159 919 919 if (!in_array($intl_tipo, ['1','2','3','4','5','6','7'], true)) $intl_tipo = ''; 920 920 921 // Failsafe: si llegamos con tipo+doc llenos pero declare!='1', asumir declare='1'. 922 // Esto cubre el caso en que el JS del checkout no setea declare='1' al forzar la sección 923 // por superar el umbral (declare está oculto pero el form envía el "0" default). 924 if ($intl_declare !== '1' && $intl_tipo !== '' && trim($intl_doc) !== '') { 925 pfwc_log('resolve_fiscal_data: failsafe ANY mode → declare="0" pero tipo+doc llenos, tratando como declarado'); 926 $intl_declare = '1'; 927 } 928 921 929 // Si el cliente declaró Documento (declare='1') y los datos están completos → procesar. 922 930 if ($intl_declare === '1' && $intl_tipo !== '' && trim($intl_doc) !== '') { -
pfacturas-for-woocommerce/tags/1.3.0.1/pFacturas.php
r3562658 r3581159 4 4 * Plugin URI: https://efactura.puntoexe.com.uy/facturaci%C3%B3n-electr%C3%B3nica/woocommerce-integrado 5 5 * Description: Electronic invoicing integration for Uruguay DGI compliance 6 * Version: 1.3.0. 06 * Version: 1.3.0.1 7 7 * Author: PuntoExe Consultores 8 8 * Author URI: https://www.puntoexe.com.uy … … 19 19 define('PFWC_PLUGIN_DIR', plugin_dir_path(__FILE__)); 20 20 define('PFWC_PLUGIN_URL', plugin_dir_url(__FILE__)); 21 define('PFWC_VERSION', '1.3.0. 0');21 define('PFWC_VERSION', '1.3.0.1'); 22 22 register_activation_hook( __FILE__, function(){ 23 23 include_once ABSPATH . 'wp-admin/includes/plugin.php'; -
pfacturas-for-woocommerce/tags/1.3.0.1/readme.txt
r3562664 r3581159 6 6 Requires PHP: 7.4 7 7 Requires Plugins: woocommerce 8 Stable tag: 1.3.0. 08 Stable tag: 1.3.0.1 9 9 License: GPLv2 or later 10 10 License URI: https://www.gnu.org/licenses/gpl-2.0.html … … 107 107 == Changelog == 108 108 109 = 1.3.0.1 = 110 * Corrección crítica: Cuando en el modo "Cualquier País" el monto del carrito supera el umbral de identificación, la emisión del CFE quedaba bloqueada con el mensaje "El monto supera el umbral de identificación. Debe completar Tipo de Documento y Documento.", aunque el cliente sí había completado los datos. Tres causas combinadas: (1) el JavaScript del checkout ocultaba el select "¿Quiere declarar Documento?" pero no forzaba su valor a "Sí" antes del envío, por lo que el formulario enviaba "No" y el backend interpretaba la orden como consumo final; (2) la validación pre-emisión del modo POS solo conocía los meta keys del modo Uruguay (`_pf_tipo_doc_pf`, `_pf_doc_pf`) y no leía los del modo "Cualquier País" (`_pf_intl_*`); (3) el mapper requería que la pregunta de declaración estuviera explícitamente en "Sí" para procesar los datos fiscales. Solucionado en los tres lugares: el JS ahora setea el value del select a "1" cuando el monto supera el umbral; la validación pre-emisión reconoce el modo "Cualquier País" y lee los meta keys correctos; y el mapper aplica un failsafe que procesa los datos si Tipo de Documento y Documento están cargados, aunque la pregunta declare no esté explícitamente en "Sí". 111 109 112 = 1.3.0.0 = 110 113 * Funcionalidad mayor: Soporte para compradores de cualquier país. Nuevo setting "País de origen de los compradores" en el tab Checkout, con dos modos: "Uruguay" (default, comportamiento estándar sin cambios) y "Cualquier País". En modo "Cualquier País" se reemplaza la pregunta "¿Factura con RUT?" y los campos asociados por una sección alternativa donde el cliente elige el tipo de documento entre 7 opciones (NIE, RUT, C.I., Pasaporte, DNI Mercosur, NIFE y Otros), cada una con su descripción visible. Cuando el monto supera el umbral de identificación se obliga a identificar; cuando no supera, se pregunta si quiere declarar Documento (texto parametrizable). Si el tipo seleccionado es RUT (Uruguay) se emite e-Factura; cualquier otro tipo se emite e-Ticket. Los tipos NIE, RUT y NIFE además solicitan Denominación Social. Tipos numéricos (NIE, RUT, C.I.) validan dígito verificador; tipos alfanuméricos (Pasaporte, DNI Mercosur, NIFE, Otros) admiten letras y números. -
pfacturas-for-woocommerce/trunk/assets/blocks.js
r3562658 r3581159 418 418 var intlEl=document.getElementById('pf_intl'); if(intlEl) intlEl.style.display='block'; 419 419 var required = tot > umbral; 420 // Cuando required=true: forzar declare='1' en el select oculto antes de leer su valor. 421 // Si no, el form envía el "0" default y el backend trata la orden como consumo final. 422 if (required) { 423 var declareSelEl = document.getElementById('pf_intl_declare'); 424 if (declareSelEl && declareSelEl.value !== '1') { declareSelEl.value = '1'; } 425 } 420 426 var declareYes = (document.getElementById('pf_intl_declare')||{}).value === '1'; 421 427 var sectionShown = required || declareYes; -
pfacturas-for-woocommerce/trunk/includes/class-pf-checkout.php
r3562658 r3581159 540 540 $script .= ' if(required){ declareField.style.setProperty("display","none","important"); }' . "\n"; 541 541 $script .= ' else { declareField.style.removeProperty("display"); }' . "\n"; 542 $script .= ' }' . "\n"; 543 $script .= ' // Cuando required=true: el select declare está oculto pero el form igual lo envía.' . "\n"; 544 $script .= ' // Forzar value="1" para que el backend reciba la declaración correctamente (no quede el "0" default).' . "\n"; 545 $script .= ' if(required){' . "\n"; 546 $script .= ' var declareSelect = by("_pf_intl_declare");' . "\n"; 547 $script .= ' if(declareSelect && declareSelect.value !== "1"){ declareSelect.value = "1"; }' . "\n"; 542 548 $script .= ' }' . "\n"; 543 549 $script .= ' // Etiqueta required visible solo si supera umbral.' . "\n"; -
pfacturas-for-woocommerce/trunk/includes/class-pf-emitter.php
r3560071 r3581159 1010 1010 $rut_flag = get_post_meta($order_id, '_pf_rut_flag', true); 1011 1011 1012 // Modo "Cualquier País" (Feature 1.3.0.0): los datos fiscales viven en metas _pf_intl_* en lugar de 1013 // los _pf_*_pf clásicos del modo UY. Validamos con la lógica intl y salimos. 1014 if (($settings['checkout_country_mode'] ?? 'UY') === 'ANY') { 1015 $intl_declare = (string) get_post_meta($order_id, '_pf_intl_declare', true); 1016 $intl_tipo = (string) get_post_meta($order_id, '_pf_intl_tipo_doc', true); 1017 $intl_doc = (string) get_post_meta($order_id, '_pf_intl_doc', true); 1018 $intl_razon = (string) get_post_meta($order_id, '_pf_intl_razon', true); 1019 1020 // Failsafe paralelo al del mapper: si hay tipo+doc llenos, asumir declarado aunque declare!='1'. 1021 $intl_has_data = ($intl_tipo !== '' && trim($intl_doc) !== ''); 1022 $intl_declared = ($intl_declare === '1') || $intl_has_data; 1023 1024 $total = abs((float)$order->get_total()); 1025 $moneda = $order->get_currency(); 1026 $umbral_ui = (float)($settings['umbral_ident'] ?? 0); 1027 $umbral = ($umbral_ui > 0) ? pfwc_calcular_umbral_en_moneda($umbral_ui, $moneda, $settings) : 0; 1028 $supera_umbral = ($umbral > 0 && $total > $umbral); 1029 1030 // Si supera umbral y no se declaró nada, bloquear. 1031 if ($supera_umbral && !$intl_declared) { 1032 return 'El monto ($' . number_format($total, 2) . ') supera el umbral de identificación ($' . number_format($umbral, 2) . '). Debe completar Tipo de Documento y Documento.'; 1033 } 1034 // Si se declaró pero faltan datos, bloquear. 1035 if ($intl_declared) { 1036 if ($intl_tipo === '') return 'Falta el Tipo de Documento para identificar al receptor del CFE.'; 1037 if (trim($intl_doc) === '') return 'Falta el Documento para identificar al receptor del CFE.'; 1038 // Tipos 1 (NIE) y 2 (RUT) → validar DV con algoritmo RUT. 1039 if (($intl_tipo === '1' || $intl_tipo === '2') && !pfwc_validar_rut($intl_doc)) { 1040 return 'El Documento "' . $intl_doc . '" no es válido. Verifique el dígito verificador.'; 1041 } 1042 // Tipo 3 (CI uruguaya) → validar DV con algoritmo CI. 1043 if ($intl_tipo === '3' && !pfwc_validar_ci($intl_doc)) { 1044 return 'La Cédula de Identidad ' . $intl_doc . ' no es válida. Verifique el dígito verificador.'; 1045 } 1046 // Tipos 1, 2, 7 (empresas): Denominación Social obligatoria. 1047 if (in_array($intl_tipo, ['1','2','7'], true) && trim($intl_razon) === '') { 1048 return 'Falta la Denominación Social para emitir el CFE de empresa.'; 1049 } 1050 } 1051 return null; // OK 1052 } 1053 1012 1054 // Heurística: si la detección previa marcó error (ej: RUT inválido + razón social con 1013 1055 // sufijo empresarial), bloquear emisión con el mensaje persistido. -
pfacturas-for-woocommerce/trunk/includes/class-pf-mapper.php
r3562658 r3581159 919 919 if (!in_array($intl_tipo, ['1','2','3','4','5','6','7'], true)) $intl_tipo = ''; 920 920 921 // Failsafe: si llegamos con tipo+doc llenos pero declare!='1', asumir declare='1'. 922 // Esto cubre el caso en que el JS del checkout no setea declare='1' al forzar la sección 923 // por superar el umbral (declare está oculto pero el form envía el "0" default). 924 if ($intl_declare !== '1' && $intl_tipo !== '' && trim($intl_doc) !== '') { 925 pfwc_log('resolve_fiscal_data: failsafe ANY mode → declare="0" pero tipo+doc llenos, tratando como declarado'); 926 $intl_declare = '1'; 927 } 928 921 929 // Si el cliente declaró Documento (declare='1') y los datos están completos → procesar. 922 930 if ($intl_declare === '1' && $intl_tipo !== '' && trim($intl_doc) !== '') { -
pfacturas-for-woocommerce/trunk/pFacturas.php
r3562658 r3581159 4 4 * Plugin URI: https://efactura.puntoexe.com.uy/facturaci%C3%B3n-electr%C3%B3nica/woocommerce-integrado 5 5 * Description: Electronic invoicing integration for Uruguay DGI compliance 6 * Version: 1.3.0. 06 * Version: 1.3.0.1 7 7 * Author: PuntoExe Consultores 8 8 * Author URI: https://www.puntoexe.com.uy … … 19 19 define('PFWC_PLUGIN_DIR', plugin_dir_path(__FILE__)); 20 20 define('PFWC_PLUGIN_URL', plugin_dir_url(__FILE__)); 21 define('PFWC_VERSION', '1.3.0. 0');21 define('PFWC_VERSION', '1.3.0.1'); 22 22 register_activation_hook( __FILE__, function(){ 23 23 include_once ABSPATH . 'wp-admin/includes/plugin.php'; -
pfacturas-for-woocommerce/trunk/readme.txt
r3562664 r3581159 6 6 Requires PHP: 7.4 7 7 Requires Plugins: woocommerce 8 Stable tag: 1.3.0. 08 Stable tag: 1.3.0.1 9 9 License: GPLv2 or later 10 10 License URI: https://www.gnu.org/licenses/gpl-2.0.html … … 107 107 == Changelog == 108 108 109 = 1.3.0.1 = 110 * Corrección crítica: Cuando en el modo "Cualquier País" el monto del carrito supera el umbral de identificación, la emisión del CFE quedaba bloqueada con el mensaje "El monto supera el umbral de identificación. Debe completar Tipo de Documento y Documento.", aunque el cliente sí había completado los datos. Tres causas combinadas: (1) el JavaScript del checkout ocultaba el select "¿Quiere declarar Documento?" pero no forzaba su valor a "Sí" antes del envío, por lo que el formulario enviaba "No" y el backend interpretaba la orden como consumo final; (2) la validación pre-emisión del modo POS solo conocía los meta keys del modo Uruguay (`_pf_tipo_doc_pf`, `_pf_doc_pf`) y no leía los del modo "Cualquier País" (`_pf_intl_*`); (3) el mapper requería que la pregunta de declaración estuviera explícitamente en "Sí" para procesar los datos fiscales. Solucionado en los tres lugares: el JS ahora setea el value del select a "1" cuando el monto supera el umbral; la validación pre-emisión reconoce el modo "Cualquier País" y lee los meta keys correctos; y el mapper aplica un failsafe que procesa los datos si Tipo de Documento y Documento están cargados, aunque la pregunta declare no esté explícitamente en "Sí". 111 109 112 = 1.3.0.0 = 110 113 * Funcionalidad mayor: Soporte para compradores de cualquier país. Nuevo setting "País de origen de los compradores" en el tab Checkout, con dos modos: "Uruguay" (default, comportamiento estándar sin cambios) y "Cualquier País". En modo "Cualquier País" se reemplaza la pregunta "¿Factura con RUT?" y los campos asociados por una sección alternativa donde el cliente elige el tipo de documento entre 7 opciones (NIE, RUT, C.I., Pasaporte, DNI Mercosur, NIFE y Otros), cada una con su descripción visible. Cuando el monto supera el umbral de identificación se obliga a identificar; cuando no supera, se pregunta si quiere declarar Documento (texto parametrizable). Si el tipo seleccionado es RUT (Uruguay) se emite e-Factura; cualquier otro tipo se emite e-Ticket. Los tipos NIE, RUT y NIFE además solicitan Denominación Social. Tipos numéricos (NIE, RUT, C.I.) validan dígito verificador; tipos alfanuméricos (Pasaporte, DNI Mercosur, NIFE, Otros) admiten letras y números.
Note:
See TracChangeset
for help on using the changeset viewer.
![(please configure the [header_logo] section in trac.ini)](/chrome/site/your_project_logo.png)