-
released this
2026-05-08 15:19:18 -04:00 | 14 commits to main since this releaseFeatures
-
Dynamic VPS stock control driven by live hypervisor capacity. Opt-in per product via WHMCS's native
tblproducts.stockcontroltoggle; when enabled, the module overwritestblproducts.qtywith the real number of VPSes the panel can still provision and WHMCS handles the "Out of Stock" badge, Add-to-Cart gating, and checkout refusal natively — no template work required. qty is derived by combining two authoritative sources:GET /packages/{packageId}for the per-VPS resource footprint (memory,cpuCores,primaryStorage,primaryStorageProfile,enabled)GET /compute/hypervisors/groups/{id}/resourcesfor live per-hypervisor free/allocated data
Algorithm sums
min(memory, cpu, storage)across eligible hypervisors (enabled AND commissioned AND !prohibit) for every group the product can be placed in (defaultconfigoption1plus every numeric value of aLocationconfigurable option), capped by the group-level IPv4 pool taken asmax()within a group to avoid double-counting. Storage matching is strict againstpackage.primaryStorageProfile; hypervisors without the named pool contribute 0. Confirmed-missing conditions (HTTP 404 on/packages/{id},package.enabled=false) force qty=0; transient failures leaveqtyUNTOUCHED to avoid false out-of-stock during API blips. -
Event-driven stock recalculation hooks:
AfterModuleCreate— refreshes qty after every VirtFusion provision (capacity just decreased). Bursts of parallel provisions coalesce via a 30 s shared rate-limit.AfterModuleTerminate— refreshes qty after every VirtFusion termination (capacity just increased). Shares the 30 s rate-limit with create.AfterCronJob— every-2-hour safety net that catches capacity changes made directly in the VirtFusion panel without going through WHMCS. Interval tunable viaSTOCK_CRON_INTERVAL_SECONDSinhooks.php.ClientAreaPageCart— opportunistic per-product refresh during the order flow, rate-limited to once per product per 60 s.
-
Order auto-accept after successful provision.
AfterModuleCreatecalls WHMCSAcceptOrder(withautosetup=falseso there's no double-provision) when the parent order is still in Pending status. Closes the gap for installs that rely on pending-order workflows for non-VF products but want VirtFusion provisions to auto-advance. Idempotent — already-accepted orders are skipped. -
Admin-triggered full recalculation. New
admin.php?action=stockRecalculateaction (POST + same-origin required) runsStockControl::recalculateAll()on demand and returns a JSON{productId: qty}map; the module log gets a compact summary ({total, updated, zeroed, skipped}) so it stays readable on stores with hundreds of products. -
Per-product safety buffer. New
stockSafetyBufferPctconfig option (configoption7, default 10) reserves X% of each resource'smaxduring stock calculation. Applied only to capped resources (unlimited resources withmax=0skip the buffer). Admins can override per product in the module settings; blank falls back to 10% so existing products get sensible headroom without any config change. -
Test Connection now probes
/compute/hypervisors/groups. A VirtFusion API token scoped only to/serverswould pass the existing/connectcheck but silently break nightly stock updates. The admin's Test Connection button now surfaces missing/computeread scope at config time with a specific error rather than as unexplained nightly silence.
Caching
- New cache keys:
pkg:{packageId}(10 min TTL, package definitions rarely change) andgrpres:{groupId}(120 s TTL, resources change minute-to-minute under load). Confirmed 404 responses are cached for 60 s so an admin re-creating a deleted package/group takes effect quickly.
Safety Properties
Module::fetchPackage()andModule::fetchGroupResources()return a tri-statearray | false | null:falsemeans "VirtFusion confirmed this doesn't exist → OOS is correct",nullmeans "we can't tell right now → don't touch existing qty". Without this distinction the module would either zero out inventory during transient API blips, or show inventory for deleted packages.\Throwablecatches on every stock-path entry point (not just\Exception) so aTypeErrorfrom a malformed API response can't escape the tri-state contract.- Stock-control is gated by
tblproducts.stockcontrol=1— products that opt out are never touched, even by the safety-net cron.
Full Changelog: v1.3.0...v1.4.0
Downloads
-