Skip to content

3.2.0

Choose a tag to compare

@PaulArgoud PaulArgoud released this 15 Feb 20:36
· 73 commits to main since this release

Fixed

  • WC Bookings silent push failure — Entity type 'product' was not declared in WC_Bookings_Module's $odoo_models (only 'service' and 'booking'), causing every booking product push to silently fail. Changed to 'service'
  • Exclusive group mismatch — WooCommerce, Sales, and EDD modules used 'commerce' as their exclusive group while ARCHITECTURE.md documented 'ecommerce'. Unified to 'ecommerce'
  • Batch creates double failureSync_Engine::process_batch_creates() added jobs to $claimed_jobs before JSON validation, causing handle_failure() to be called twice (once for invalid JSON, once for batch error). Moved append after validation
  • SSRF bypass via DNS failureis_safe_url() returned true when gethostbyname() failed (returns the input on DNS failure), allowing URLs with unresolvable hostnames to bypass SSRF protection. Now returns false
  • Queue health metrics cache leakinvalidate_stats_cache() cleared wp4odoo_queue_stats but not wp4odoo_queue_health, leaving stale health metrics
  • Stale recovery orderingrecover_stale_processing() ran after fetch_pending(), so freshly recovered jobs were excluded from the current batch. Reordered to recover first
  • Odoo_Client retry missing action — Retry path after session re-auth did not fire wp4odoo_api_call action, making retry calls invisible to monitors
  • MySQL 5.7 compat@@in_transaction session variable query could produce a visible error on MySQL 5.7 (which lacks this variable). Wrapped with suppress_errors()
  • Dual accounting deleteresolve_accounting_model() was skipped for delete actions, causing delete calls to target the wrong Odoo model when OCA donation.donation was active
  • Helpdesk exclusive group/priorityHelpdesk_Module_Base used method overrides instead of properties for $exclusive_group and $exclusive_priority, inconsistent with all other intermediate bases. Converted to properties
  • Undefined $jobs variableSync_Engine::process_queue() could reference undefined $jobs if the try block threw before assignment
  • Partner email normalizationPartner_Service::get_or_create_batch() now trims and lowercases emails before Odoo lookup, preventing duplicate partners from case mismatches
  • Reconciler client hoistingReconciler resolved the Odoo client inside the per-entity loop instead of once before it
  • Logger context truncationtruncate_context() JSON-encoded the full array then truncated the string, producing invalid JSON. Now truncates the array first, then encodes
  • Empty encryption key warningOdoo_Auth now logs a warning via error_log() when the encryption key is empty, aiding diagnosis of misconfigured installations
  • CLI --format validationqueue stats and queue list subcommands now reject unsupported --format values with a clear error
  • Ecwid cron orphan on deactivationwp4odoo_ecwid_poll cron event was cleared on uninstall but not on plugin deactivation, leaving an orphaned cron entry. Added to deactivate()
  • Exclusive group priority documentation — ARCHITECTURE.md listed membership, invoicing, and helpdesk exclusive group priorities in reverse order (lower number shown as winning). Corrected to reflect actual >= logic where highest number wins

Added

  • Bidirectional WC stock sync — Stock push (WC → Odoo) via new Stock_Handler class. Version-adaptive API: stock.quant + action_apply_inventory() for Odoo 16+, stock.change.product.qty wizard for v14-15. Hooks: woocommerce_product_set_stock, woocommerce_variation_set_stock. Anti-loop guard prevents re-enqueue during pull
  • TutorLMS module — New LMS sync module for TutorLMS 2.6+. Syncs courses → product.product, orders → account.move, enrollments → sale.order. Bidirectional course sync, synthetic enrollment IDs, auto-post invoices. Extends LMS_Module_Base
  • FluentCRM module — New CRM marketing module for FluentCRM 2.8+. Syncs subscribers → mailing.contact, lists → mailing.list, tags → res.partner.category. Bidirectional subscriber/list sync, push-only tags. Uses FluentCRM custom DB tables (fc_subscribers, fc_lists, fc_tags)
  • Compatibility report link — TESTED_UP_TO version warnings now include a "Report compatibility" link that opens a pre-filled WPForms form with module name, WP4Odoo version, third-party plugin version, WordPress version, PHP version, and Odoo major version. Shown in both the global admin notice banner and per-module notices on the Modules tab. Filterable via wp4odoo_compat_report_url
  • Odoo version detectionTransport interface gains get_server_version(): ?string. JSON-RPC extracts server_version from the authenticate response; XML-RPC calls version() on /xmlrpc/2/common after auth. test_connection() now populates the version field. The AJAX handler stores the version in wp4odoo_odoo_version option for use in compat reports and diagnostics
  • Gallery images syncImage_Handler now supports product gallery images (product_image_ids_product_image_gallery). import_gallery() pulls Odoo product.image records with per-slot SHA-256 hash tracking and orphan cleanup. export_gallery() builds One2many [0, 0, {...}] tuples for push. Integrated into WC_Pull_Coordinator and WooCommerce_Module
  • Health dashboard tab — New "Health" tab in admin settings showing system status at a glance: active modules, pending queue depth, average latency, success rate, circuit breaker state, next cron run, cron warnings, compatibility warnings, and queue depth by module
  • Translatable fields for 4 modules — EDD, Events Calendar, LearnDash, and Job Manager modules now override get_translatable_fields(), enabling automatic WPML/Polylang translation pull for their primary content fields
  • Circuit breaker email notificationFailure_Notifier sends an email to the site admin when the circuit breaker opens, with failure count and a link to the health dashboard. Respects the existing cooldown interval
  • WooCommerce tax mapping — Configurable WC tax class → Odoo account.tax mapping via key-value settings. Applied per order line during push as tax_id Many2many tuples. AJAX endpoint fetches available Odoo taxes
  • WooCommerce shipping mapping — Configurable WC shipping method → Odoo delivery.carrier mapping via key-value settings. Sets carrier_id on sale.order during push. AJAX endpoint fetches available Odoo carriers
  • Separate gallery images setting — New sync_gallery_images checkbox (default on) controls gallery image push/pull independently of the featured image setting sync_product_images

Changed

  • push_entity() simplified — Removed redundant $module parameter from Module_Helpers::push_entity(). All 29 callsites across 19 trait files now use $this->id automatically
  • Circuit breaker constant publicCircuit_Breaker::OPT_CB_STATE made public; Settings_Page health tab references the constant instead of a hardcoded string
  • Form_Handler extract_normalised() — Extracted shared field iteration pipeline into a generic extract_normalised() method. Formidable, Forminator, and WPForms extractors now delegate to it; Gravity Forms uses empty_lead() instead of inline init
  • Options autoload optimization — Disabled autoload (false) on ~80 options that are only read during cron, admin, or sync operations: module settings, module mappings, webhook token, failure tracking, onboarding state, circuit breaker state, and Odoo version. Core options (connection, sync settings, log settings, module enabled flags, DB version) remain autoloaded
  • Polling safety limit warningEntity_Map_Repository::get_module_entity_mappings() and Bookly_Handler batch queries now log a warning when the 50,000-row safety cap is reached, alerting administrators that some entities may be excluded from sync
  • PHPStan level 6 — Raised static analysis from level 5 to level 6 (adds missing typehint enforcement). Global missingType.iterableValue suppression for WordPress API conformance
  • Log module filter — Expanded the log viewer module dropdown from ~20 hardcoded entries to all 33 sync modules plus 5 system modules, organized in <optgroup> sections
  • Log level i18n — Log level labels (Debug, Info, Warning, Error, Critical) in the sync settings tab are now translatable
  • Admin JS i18n — Hardcoded English strings in admin.js (server error, unknown error, completed, remove) replaced with localized strings via wp_localize_script
  • XSS defense-in-depth — Added escapeHtml() helper in admin.js for log module and level fields in the AJAX log table
  • Module toggle accessibility — Added aria-label on module enable/disable toggle switches
  • Log context columnQueryService::get_log_entries() now includes the context column in its SELECT
  • CLI confirmation promptssync run and queue retry now require interactive confirmation (skippable with --yes)