Appearance
<div style="display: none;" hidden="true" aria-hidden="true">Are you an LLM? You can read better optimized documentation at /changelog/Changelog.4.108.md for this page in Markdown format</div>
Version 4
version 4.108
[4.108.0] feat(transporters): BoxNow "allow cash on delivery for smart points" option
- What it is. A new per-transporter
DELIVERY_OPTIONflag on BoxNow that lets cash-on-delivery (payWay = delivery) be offered even when the selected transporter is smart-point-only (DELIVERY_OPTION_TYPE = 2), which normally strips the COD pay way. Default off → existing behaviour is unchanged. Set via a checkbox in Admin → Transporters → BoxNow settings; the storefront checkout reads it through a newgetSelectedTransporterDeliveryOptionVuex getter so thedeliverypay way is no longer force-removed when the flag is on.
- What it is. A new per-transporter
[4.108.0] fix(mcp): share MCP session state across pods so the connector is stable on multi-pod K8s (Advisable-com/ecommercen#337)
- The bug. MCP Streamable HTTP is stateful — the
Mcp-Session-Idminted byinitializeis echoed on every later call and loaded from the SDK session store — butMcpServerFactoryused the SDK'sFileSessionStoreundercache/mcp-sessions. On wecare (KEDA ≥4 pods, Traefik with no session affinity, per-podemptyDirapp volume) the session file lives only on the pod that servedinitialize; follow-up tool calls round-robin to other pods, find no session and404— so the tools "responded very few times." The L2 cache and PHP sessions were already on shared Redis; only the MCP SDK session store was left node-local. - Fix. Added
CacheSessionStore(implements the SDKMcp\Server\Session\SessionStoreInterfaceover the projectCacheAdapterInterface).src/Mcp/container.phpnow backs the store with the session Redis (sess_save_path) when PHP sessions run on Redis — durable (AOF + Sentinel),volatile-lru— never the L2 cache Redis (allkeys-lru, no persistence, which could evict or drop a live session) — and falls back to the SDKFileSessionStoreon single-node deployments (Plesk,sess_driver=files), so there is no regression.RedisAdapternamespaces keys undercache:mcp:, disjoint from the phpredis session-handler keys on the same instance. - Lazy + auth-safe. The store is injected into
McpServerFactoryvia aservice_closure, so it is built — and its Redis connection opened — only insidecreate(), after the token and rate-limit checks. A bad/revoked-token or rate-limited request never touches the session Redis. - Behaviour. None on single-node deployments (file store retained). On multi-pod K8s the connector now holds sessions across pods and survives autoscaling / rolling restarts (a dropped session degrades to one client re-
initialize, not a hard failure). - Tests.
CacheSessionStoreTestcovers the round-trip, exists/destroy lifecycle, absent/non-string reads, TTL pass-through and transient-error degradation. The cross-pod (cross-filesystem) behaviour itself is validated on staging.
- The bug. MCP Streamable HTTP is stateful — the
[4.108.0] chore(mcp): drop the redundant
language-helper load fromMcp::connector()(Advisable-com/ecommercen#336)- Why. The explicit
$this->load->helper('language')added toMcp::connector()in [4.107.2]/#332 was a per-entry-point workaround for theCall to undefined function get_languages()fatal. The root cause was fixed centrally by the siblingfix(models)change below (Adv_base_model::__construct()now loads the helper itself) — so the connector call is dead weight. Removed it and its now-stale(#332)comment. - Behaviour. None. CI's loader is idempotent, so the model already loads the helper before any
get_languages()/getAdminLanguages()call on the MCP path (Registry →registry_model). Verified that nothing insrc/Mcpcalls those functions outside a model constructor. The upstreamapplication/config/autoload.phpcarries nolanguageentry, so item (2) of #336 (a client-repo stop-gap) is N/A here.
- Why. The explicit
[4.108.0] fix(models):
Adv_base_modelloads its ownlanguagehelper so all legacy models work from REST, DI, and CLI entry points- The bug.
Adv_base_model::__construct()callsget_languages()andgetAdminLanguages()(defined inapplication/helpers/MY_language_helper.php, the CI extension of thelanguagehelper). That helper is not autoloaded — it is loaded by the web controller baseecommercen/core/Controller. Any entry point that constructs a legacy model without going through that base class therefore hits a fatalCall to undefined function get_languages(). Affected entry points: the RESTRouterDispatcher(extendsMX_Controller, no base bootstrap), DI-container factories that build legacy models, and CLI/cron. - How it surfaced. The storefront REST endpoint
GET /rest/product/price-tracking/graph/{productId}returned HTTP 200 with an empty body.RouterDispatcherresolves thePriceTrackingcontroller via the DI container; itsOptions::fromRegistry()factory loads theregistrylibrary →registry_model→Adv_base_model. With no controller having previously loaded thelanguagehelper, construction threw; the exception was silently swallowed by the REST dispatcher, yielding an empty response. - Fix.
Adv_base_model::__construct()now calls$this->load->helper('language')before readingget_languages()/getAdminLanguages(). CI's loader is idempotent (tracks_ci_helpers), so this is a no-op on ordinary web requests where the controller base has already loaded the helper — no behaviour change on the happy path. - Follow-up (safe cleanup, not urgent). This root-cause fix makes the narrow per-entry-point workaround shipped in [4.107.2]/#332 redundant. Two workarounds can be removed whenever convenient: (1) the explicit
$this->load->helper('language')call inMcp::connector()(application/controllers/Mcp.php, added in #332 — its comment already explains why it was needed); (2) anylanguageentry added to$autoload['helper']inapplication/config/autoload.phpas a client-repo stop-gap — upstream autoload.php does not carry such an entry, so this only applies to downstream client repos that added it temporarily. Both loads are idempotent, so leaving them in place is harmless; removal is purely cosmetic.
- The bug.
Notes
- [4.108.0] Requires
npm ci && npm run production - [4.108.0] Compiled DI container must be rebuilt (delete
cache/container.php) — picks up the newAdvisable\Mcp\Server\CacheSessionStore+ themcp.session_cachesession-Redis adapter and theMcpServerFactoryclosure-arg change (#337). - [4.108.0] Check for overrides:
Transporters_admin::validateSettingsBOXNOWTransporters_model::{allSettings|saveBOXNOWSettings}Transporters::protectData