feat: add getDailyConversions() — demo boots, downloads, abandoned carts

Daily time-series data for conversion funnel metrics, compatible with
NVD3 chart format. Abandoned carts = visited cart but no order confirmation.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-04-04 19:38:00 +00:00
parent 633d56a39e
commit ac0b241bb6

View File

@@ -237,6 +237,88 @@ class VisitorStats
) ?: [];
}
/**
* Get daily demo boots + demo downloads + abandoned carts for charting.
*
* @param string $dateFrom Y-m-d
* @param string $dateTo Y-m-d
* @return array ['demo_boots' => [[ts,val],...], 'demo_downloads' => [...], 'abandoned_carts' => [...]]
*/
public static function getDailyConversions(string $dateFrom, string $dateTo): array
{
$db = \Db::getInstance((bool) _PS_USE_SQL_SLAVE_);
$prefix = _DB_PREFIX_;
// Demo boots
$bootRows = $db->executeS(
"SELECT DATE(date_add) as day, COUNT(*) as cnt
FROM `{$prefix}mprdigitalrevolution_demo_boot`
WHERE date_add >= '" . pSQL($dateFrom) . " 00:00:00'
AND date_add <= '" . pSQL($dateTo) . " 23:59:59'
GROUP BY DATE(date_add)"
) ?: [];
// Demo downloads
$dlRows = $db->executeS(
"SELECT DATE(date_add) as day, COUNT(*) as cnt
FROM `{$prefix}mprdigitalrevolution_demo_request`
WHERE date_add >= '" . pSQL($dateFrom) . " 00:00:00'
AND date_add <= '" . pSQL($dateTo) . " 23:59:59'
GROUP BY DATE(date_add)"
) ?: [];
// Abandoned carts: visitors who viewed cart (page_type=5) but NOT order confirmation (page_type=7)
$cartRows = $db->executeS(
"SELECT DATE(s.date_add) as day, COUNT(DISTINCT s.ip_address) as cnt
FROM `{$prefix}mpr_sessions` s
JOIN `{$prefix}mpr_page_views` pv ON s.id_session = pv.id_session AND pv.page_type = 5
LEFT JOIN `{$prefix}mpr_page_views` pv2 ON s.id_session = pv2.id_session AND pv2.page_type = 7
WHERE s.is_bot = 0 AND s.js_verified = 1
AND s.date_add >= '" . pSQL($dateFrom) . " 00:00:00'
AND s.date_add <= '" . pSQL($dateTo) . " 23:59:59'
AND pv2.id_page_view IS NULL
GROUP BY DATE(s.date_add)"
) ?: [];
// Index by day
$byDay = ['boots' => [], 'downloads' => [], 'carts' => []];
foreach ($bootRows as $r) $byDay['boots'][$r['day']] = (int) $r['cnt'];
foreach ($dlRows as $r) $byDay['downloads'][$r['day']] = (int) $r['cnt'];
foreach ($cartRows as $r) $byDay['carts'][$r['day']] = (int) $r['cnt'];
// Fill dates
$boots = $downloads = $carts = [];
$date = new \DateTime($dateFrom);
$end = new \DateTime($dateTo);
while ($date <= $end) {
$key = $date->format('Y-m-d');
$ts = $date->getTimestamp();
$boots[] = [$ts, $byDay['boots'][$key] ?? 0];
$downloads[] = [$ts, $byDay['downloads'][$key] ?? 0];
$carts[] = [$ts, $byDay['carts'][$key] ?? 0];
$date->modify('+1 day');
}
return [
'demo_boots' => $boots,
'demo_downloads' => $downloads,
'abandoned_carts' => $carts,
];
}
/**
* Get conversion totals for a date range.
*/
public static function getConversionTotals(string $dateFrom, string $dateTo): array
{
$data = self::getDailyConversions($dateFrom, $dateTo);
$totals = [];
foreach ($data as $key => $points) {
$totals[$key] = array_sum(array_column($points, 1));
}
return $totals;
}
/**
* Get full dashboard payload (for AJAX).
*/