init();
}, 90);
}
protected function init()
{
$drivers = DriverManager::getEnabled();
if (!$drivers) {
return false;
}
// Boot only enabled drivers (available + toggled on in settings)
foreach ($drivers as $driver) {
$driver->register();
$driver->registerAutomationTrigger();
}
// Expose abandon cart availability to the frontend via fcAdmin vars
add_filter('fluent_crm/admin_vars', function ($vars) {
$vars['has_abandon_carts'] = true;
$vars['can_read_abandon_carts'] = PermissionManager::currentUserCan('fcrm_read_funnels');
return $vars;
});
// Add Abandoned Carts as a sub-item under the Reports dropdown
add_filter('fluent_crm/menu_items', function ($items) {
if (!PermissionManager::currentUserCan('fcrm_read_funnels')) {
return $items;
}
$urlBase = fluentcrm_menu_url_base();
$hasReportsMenu = false;
foreach ($items as &$item) {
if (!empty($item['key']) && $item['key'] === 'reports' && isset($item['sub_items'])) {
$item['sub_items'][] = [
'key' => 'reports_abandoned_carts',
'label' => __('Abandoned Carts', 'fluent-crm'),
'permalink' => $urlBase . 'reports?tab=abandoned_carts',
'icon' => '',
];
$hasReportsMenu = true;
break;
}
}
unset($item);
if (!$hasReportsMenu) {
$items[] = [
'key' => 'reports',
'label' => __('Reports', 'fluent-crm'),
'permalink' => $urlBase . 'reports?tab=abandoned_carts',
'layout_class' => 'fc_1_col_menu',
'sub_items' => [
[
'key' => 'reports_abandoned_carts',
'label' => __('Abandoned Carts', 'fluent-crm'),
'permalink' => $urlBase . 'reports?tab=abandoned_carts',
'icon' => '',
]
],
];
}
return $items;
});
// Run the runner
add_action('fluentcrm_scheduled_five_minute_tasks', [$this, 'maybeRunAbRunner'], 999);
add_action('fluentcrm_scheduled_daily_tasks', [$this, 'markOldCartsAsLost'], 10);
add_filter('fluent_crm/sales_stats', function ($stats) {
[$recoveredCount, $recoveredRevenue] = AbCartHelper::getCountAndSumByStatus('recovered', [], 'recovered_at');
if (!$recoveredRevenue) {
return $stats;
}
$dateRange = [
gmdate('Y-m-01 00:00:00', current_time('timestamp')),
gmdate('Y-m-t 23:59:59', current_time('timestamp'))
];
[$thisMonth, $thisMonthRevenue] = AbCartHelper::getCountAndSumByStatus('recovered', $dateRange, 'recovered_at');
$stats[] = [
'title' => __('Cart Recovered (This Month)', 'fluent-crm'),
'content' => DriverManager::formatPrice($thisMonthRevenue)
];
$stats[] = [
'title' => __('Cart Recovered (All Time)', 'fluent-crm'),
'content' => DriverManager::formatPrice($recoveredRevenue)
];
return $stats;
});
}
public function maybeRunAbRunner()
{
static $counter = 0;
if (!$counter) {
if (fluentCrmIsTimeOut(30)) {
return false;
}
// It's the first time. Check if there has any runner or not
$lastRunner = fluentCrmGetOptionCache('__fc_ab_runner');
if ($lastRunner) {
$timeElapsed = time() - $lastRunner;
if ($timeElapsed < 50) {
return false;
}
fluentCrmSetOptionCache('__fc_ab_runner', null, 50);
}
}
fluentCrmSetOptionCache('__fc_ab_runner', time(), 50);
$counter = $counter + 1;
// Get Draft Carts that need to be abandoned
$settings = AbCartHelper::getSettings();
$cutMinutes = Arr::get($settings, 'capture_after_minutes', 5);
$cutDateTime = gmdate('Y-m-d H:i:s', current_time('timestamp') - ($cutMinutes * 60));
$enabledSlugs = DriverManager::getEnabledSlugs();
if (!$enabledSlugs) {
fluentCrmSetOptionCache('__fc_ab_runner', null, 50);
return false;
}
$abCarts = AbandonCartModel::where('status', 'draft')
->whereIn('provider', $enabledSlugs)
->where('updated_at', '<=', $cutDateTime)
->orderBy('id', 'DESC')
->limit(10)
->get();
if ($abCarts->isEmpty()) {
fluentCrmSetOptionCache('__fc_ab_runner', null, 50);
return false;
}
foreach ($abCarts as $abCart) {
(new AbandonCartRunner())->runAbandonCart($abCart);
}
fluentCrmSetOptionCache('__fc_ab_runner', null, 50);
if (!fluentCrmIsTimeOut(40)) {
$this->maybeRunAbRunner();
}
return true;
}
public function markOldCartsAsLost()
{
$settings = AbCartHelper::getSettings();
$cutDays = Arr::get($settings, 'lost_cart_days', 15);
$cutDateTime = gmdate('Y-m-d H:i:s', current_time('timestamp') - ($cutDays * 86400));
AbandonCartModel::where('status', 'processing')
->where('created_at', '<=', $cutDateTime)
->update(['status' => 'lost']);
}
}