Skip to content

3.5.0

Choose a tag to compare

@PaulArgoud PaulArgoud released this 18 Feb 03:06
· 46 commits to main since this release

Added

  • WordPress Multisite → Multi-company Odoo — Full multisite support: each site in a WordPress network syncs with a specific Odoo company (res.company). Migration 7 adds blog_id column to wp4odoo_entity_map, wp4odoo_sync_queue, and wp4odoo_logs tables. Repository layer (Entity_Map_Repository, Sync_Queue_Repository, Logger) scopes all queries by blog_id. Odoo_Client injects allowed_company_ids into kwargs context when company_id > 0. Network activation iterates all sites, wp_initialize_site hook provisions new sites. Backward compatible: DEFAULT 1 ensures single-site installs are unaffected
  • Network Admin page — Centralized settings page in the WordPress network admin for shared Odoo connection (URL, DB, user, API key, protocol, timeout) and site → company_id mapping. Individual sites inherit the network connection by default but can override with their own connection in Settings > Odoo Connector
  • JetBooking module — New booking module for JetBooking (Crocoblock) 3.0+. Extends Booking_Module_Base. Syncs services → product.product (bidirectional), bookings → calendar.event (push). Hybrid data access: CPT for services, custom table jet_apartment_bookings for bookings. Hooks: jet-abaf/db/booking/after-insert, jet-abaf/db/booking/after-update, save_post_{service_cpt}
  • WP ERP CRM module — New CRM module for WP ERP 1.6+. Syncs contacts → crm.lead (bidirectional), activities → mail.activity (push). Custom table access (erp_peoples, erp_crm_customer_activities). Activity type resolution via mail.activity.type (cached). Cross-module partner linking with existing CRM module via email lookup. Life stage mapping: subscriber/lead → lead, opportunity → opportunity, customer → won
  • JetEngine Meta-Module — New meta-module for JetEngine (Crocoblock) 3.0+. Enriches other modules' sync pipelines with JetEngine meta-fields (pattern identical to ACF meta-module). Admin-configured mappings: target_module, entity_type, jet_field, odoo_field, type. Registers wp4odoo_map_to_odoo_*, wp4odoo_map_from_odoo_*, and wp4odoo_after_save_* filters at boot. No own entity types
  • JetFormBuilder support — 8th form plugin in the Forms module. Hooks into jet-form-builder/form-handler/after-send. Key-value data extraction via strategy pattern (same as Fluent Forms). Detection: JET_FORM_BUILDER_VERSION constant
  • Odoo_Model enum additions — 2 new cases: MailActivity, MailActivityType
  • WP-CLI --blog_id parameterwp wp4odoo sync run --blog_id=3 and wp wp4odoo reconcile crm contact --blog_id=3 target a specific site in multisite (switches blog context, flushes credential cache)

Added (Architecture)

  • Migration 8 — Stale recovery index — New composite index idx_stale_recovery (blog_id, status, processed_at) on wp4odoo_sync_queue for efficient stale job recovery queries. Idempotent (checks SHOW INDEX before ALTER)
  • Migration 9 — Rebuild indexes with blog_id prefix — Rebuilds idx_dedup_odoo on wp4odoo_sync_queue and idx_poll_detection on wp4odoo_entity_map with blog_id as leading column for correct multisite index scoping. Idempotent (checks SHOW INDEX before DROP)
  • Migration 10 — Logs cleanup index + drop obsolete index — Adds idx_blog_cleanup (blog_id, created_at) on wp4odoo_logs for efficient multisite log cleanup. Drops obsolete idx_dedup_composite from wp4odoo_sync_queue (redundant since migration 7 added blog_id to dedup indexes)
  • Logger::for_channel() factory — New static factory method creates Logger instances with a shared Settings_Repository (avoids repeated get_option() calls when multiple loggers are created in the same request). All 12 direct new Logger() callsites migrated to Logger::for_channel() (Sync_Engine, Queue_Manager, Module_Base, Webhook_Handler, Partner_Service, Odoo_Client, Odoo_Transport_Base, Odoo_Auth, CLI, Ajax_Monitor_Handlers, Translation_Service)
  • Module_Base::register_hook() / teardown() — New hook lifecycle methods. register_hook() wraps add_action() with safe_callback() and tracks registered hooks. teardown() removes all tracked hooks via remove_action(). Called automatically when a module is disabled via the admin toggle. Designed for gradual adoption by new modules
  • Queue_Manager injectable Logger — Constructor accepts optional ?Logger $logger parameter. When provided (e.g. by Sync_Engine), queue depth alerts share the caller's Logger and its correlation ID. Falls back to Logger::for_channel('queue_manager') when null

Removed

  • exclusive_priority dead code — Removed $exclusive_priority property and get_exclusive_priority() getter from Module_Base and 17 module classes. Module_Registry::register() never read this value — exclusive groups use first-registered-wins based on registration order, not priority

Fixed (Architecture)

  • Blog-scoped transientsSync_Engine stale recovery transient (wp4odoo_last_stale_recovery) and Queue_Manager depth check cooldown now include get_current_blog_id() in their transient keys, preventing multisite sites from sharing cooldown state
  • Webhook token auto-migrationSettings_Repository::get_webhook_token() now auto-encrypts plaintext tokens on first read (backward-compat fallback path). Subsequent reads return the encrypted-then-decrypted value, eliminating the plaintext storage after first access
  • Multisite index scopingidx_dedup_odoo and idx_poll_detection indexes were missing blog_id as leading column, causing full-index scans in multisite installations. Migration 9 rebuilds both with correct blog_id prefix
  • SSRF protection on Network Admin — Network_Admin URL input now passes through Settings_Validator::is_safe_url() (same SSRF check as Settings_Page), rejecting private/internal IP addresses. is_safe_url() and is_private_ip() extracted from Settings_Page to shared Settings_Validator
  • Encryption key empty saltOdoo_Auth::get_encryption_key() now throws RuntimeException when both AUTH_KEY and SECURE_AUTH_KEY are empty, instead of silently deriving a predictable key from SHA256('')
  • Batch JSON error classificationBatch_Create_Processor now classifies invalid JSON payloads as Error_Type::Transient (retryable) instead of Permanent, consistent with Sync_Engine::process_job() behavior
  • AJAX exception message sanitizationAjax_Data_Handlers (fetch_odoo_taxes, fetch_odoo_carriers) no longer exposes raw exception messages to the browser. Errors are logged via Logger::for_channel('admin') and a generic translated message is returned to the client

Changed

  • Settings_Repository multisite support — New methods: get_effective_connection() (local → network fallback), get_network_connection(), save_network_connection(), get_site_company_id(), get_network_site_companies(), save_network_site_companies(), is_using_network_connection(). New constants: OPT_NETWORK_CONNECTION, OPT_NETWORK_SITE_COMPANIES. company_id added to DEFAULTS_CONNECTION
  • Odoo_Auth multisite credential resolutionget_credentials() falls back to network-level shared connection when site has no local URL configured. Applies site-specific company_id from network mapping. save_credentials() preserves company_id
  • Sync_Engine lock scoping — Advisory lock names include blog_id: wp4odoo_sync_{blog_id} and wp4odoo_sync_{blog_id}_{module} for multisite isolation
  • Connection tab UI — Shows "Using network connection" indicator when site inherits from network. New Company ID input field after Timeout

Tests

  • 4 188 unit tests (6 445 assertions) — new tests covering multisite blog_id scoping (Entity_Map_Repository, Sync_Queue_Repository), company_id injection (Odoo_Client), credential resolution (Odoo_Auth network fallback), Settings_Repository multisite methods, switch_to_blog stubs, JetBooking module+handler, WP ERP CRM module+handler, JetEngine Meta-Module, JetFormBuilder form extraction, migrations 7–10, webhook token auto-migration