Plugin Directory

Changeset 3581159


Ignore:
Timestamp:
06/22/2026 04:28:47 AM (4 months ago)
Author:
puntoexeconsultores
Message:

Release 1.3.0.1 - Fix critico modo 'Cualquier Pais': cuando el monto supera el umbral de identificacion, la emision quedaba bloqueada aunque el cliente hubiera cargado Tipo y Documento. Tres causas combinadas resueltas: (1) JS ahora fuerza declare='1' al ocultar el select por umbral; (2) validate_fiscal_pre_emit reconoce modo ANY y lee metas _pf_intl_*; (3) mapper failsafe procesa datos si tipo+doc estan llenos aunque declare no sea explicito.

Location:
pfacturas-for-woocommerce
Files:
12 edited
1 copied

Legend:

Unmodified
Added
Removed
  • pfacturas-for-woocommerce/tags/1.3.0.1/assets/blocks.js

    r3562658 r3581159  
    418418        var intlEl=document.getElementById('pf_intl'); if(intlEl) intlEl.style.display='block';
    419419        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        }
    420426        var declareYes = (document.getElementById('pf_intl_declare')||{}).value === '1';
    421427        var sectionShown = required || declareYes;
  • pfacturas-for-woocommerce/tags/1.3.0.1/includes/class-pf-checkout.php

    r3562658 r3581159  
    540540    $script .= '      if(required){ declareField.style.setProperty("display","none","important"); }' . "\n";
    541541    $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";
    542548    $script .= '    }' . "\n";
    543549    $script .= '    // Etiqueta required visible solo si supera umbral.' . "\n";
  • pfacturas-for-woocommerce/tags/1.3.0.1/includes/class-pf-emitter.php

    r3560071 r3581159  
    10101010    $rut_flag = get_post_meta($order_id, '_pf_rut_flag', true);
    10111011
     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
    10121054    // Heurística: si la detección previa marcó error (ej: RUT inválido + razón social con
    10131055    // sufijo empresarial), bloquear emisión con el mensaje persistido.
  • pfacturas-for-woocommerce/tags/1.3.0.1/includes/class-pf-mapper.php

    r3562658 r3581159  
    919919      if (!in_array($intl_tipo, ['1','2','3','4','5','6','7'], true)) $intl_tipo = '';
    920920
     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
    921929      // Si el cliente declaró Documento (declare='1') y los datos están completos → procesar.
    922930      if ($intl_declare === '1' && $intl_tipo !== '' && trim($intl_doc) !== '') {
  • pfacturas-for-woocommerce/tags/1.3.0.1/pFacturas.php

    r3562658 r3581159  
    44 * Plugin URI: https://efactura.puntoexe.com.uy/facturaci%C3%B3n-electr%C3%B3nica/woocommerce-integrado
    55 * Description: Electronic invoicing integration for Uruguay DGI compliance
    6  * Version: 1.3.0.0
     6 * Version: 1.3.0.1
    77 * Author: PuntoExe Consultores
    88 * Author URI: https://www.puntoexe.com.uy
    … …  
    1919define('PFWC_PLUGIN_DIR', plugin_dir_path(__FILE__));
    2020define('PFWC_PLUGIN_URL', plugin_dir_url(__FILE__));
    21 define('PFWC_VERSION', '1.3.0.0');
     21define('PFWC_VERSION', '1.3.0.1');
    2222register_activation_hook( __FILE__, function(){
    2323    include_once ABSPATH . 'wp-admin/includes/plugin.php';
  • pfacturas-for-woocommerce/tags/1.3.0.1/readme.txt

    r3562664 r3581159  
    66Requires PHP: 7.4
    77Requires Plugins: woocommerce
    8 Stable tag: 1.3.0.0
     8Stable tag: 1.3.0.1
    99License: GPLv2 or later
    1010License URI: https://www.gnu.org/licenses/gpl-2.0.html
    … …  
    107107== Changelog ==
    108108
     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
    109112= 1.3.0.0 =
    110113* 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  
    418418        var intlEl=document.getElementById('pf_intl'); if(intlEl) intlEl.style.display='block';
    419419        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        }
    420426        var declareYes = (document.getElementById('pf_intl_declare')||{}).value === '1';
    421427        var sectionShown = required || declareYes;
  • pfacturas-for-woocommerce/trunk/includes/class-pf-checkout.php

    r3562658 r3581159  
    540540    $script .= '      if(required){ declareField.style.setProperty("display","none","important"); }' . "\n";
    541541    $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";
    542548    $script .= '    }' . "\n";
    543549    $script .= '    // Etiqueta required visible solo si supera umbral.' . "\n";
  • pfacturas-for-woocommerce/trunk/includes/class-pf-emitter.php

    r3560071 r3581159  
    10101010    $rut_flag = get_post_meta($order_id, '_pf_rut_flag', true);
    10111011
     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
    10121054    // Heurística: si la detección previa marcó error (ej: RUT inválido + razón social con
    10131055    // sufijo empresarial), bloquear emisión con el mensaje persistido.
  • pfacturas-for-woocommerce/trunk/includes/class-pf-mapper.php

    r3562658 r3581159  
    919919      if (!in_array($intl_tipo, ['1','2','3','4','5','6','7'], true)) $intl_tipo = '';
    920920
     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
    921929      // Si el cliente declaró Documento (declare='1') y los datos están completos → procesar.
    922930      if ($intl_declare === '1' && $intl_tipo !== '' && trim($intl_doc) !== '') {
  • pfacturas-for-woocommerce/trunk/pFacturas.php

    r3562658 r3581159  
    44 * Plugin URI: https://efactura.puntoexe.com.uy/facturaci%C3%B3n-electr%C3%B3nica/woocommerce-integrado
    55 * Description: Electronic invoicing integration for Uruguay DGI compliance
    6  * Version: 1.3.0.0
     6 * Version: 1.3.0.1
    77 * Author: PuntoExe Consultores
    88 * Author URI: https://www.puntoexe.com.uy
    … …  
    1919define('PFWC_PLUGIN_DIR', plugin_dir_path(__FILE__));
    2020define('PFWC_PLUGIN_URL', plugin_dir_url(__FILE__));
    21 define('PFWC_VERSION', '1.3.0.0');
     21define('PFWC_VERSION', '1.3.0.1');
    2222register_activation_hook( __FILE__, function(){
    2323    include_once ABSPATH . 'wp-admin/includes/plugin.php';
  • pfacturas-for-woocommerce/trunk/readme.txt

    r3562664 r3581159  
    66Requires PHP: 7.4
    77Requires Plugins: woocommerce
    8 Stable tag: 1.3.0.0
     8Stable tag: 1.3.0.1
    99License: GPLv2 or later
    1010License URI: https://www.gnu.org/licenses/gpl-2.0.html
    … …  
    107107== Changelog ==
    108108
     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
    109112= 1.3.0.0 =
    110113* 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.