Files
gustavoo-me/wp-content/plugins/fluent-crm/app/Modules/AbandonCart/AbandonCartController.php
T
2026-07-23 22:56:30 -03:00

237 lines
8.7 KiB
PHP

<?php
namespace FluentCrm\App\Modules\AbandonCart;
use FluentCrm\App\Modules\AbandonCart\Drivers\DriverManager;
use FluentCrm\App\Http\Controllers\Controller;
use FluentCrm\App\Models\Funnel;
use FluentCrm\App\Services\Helper;
use FluentCrm\Framework\Http\Request\Request;
use FluentCrm\Framework\Support\Arr;
class AbandonCartController extends Controller
{
public function getCarts(Request $request)
{
$query = $request->get('query', []);
$dateRangeInput = $request->get('date_range', []);
$dateRange = $this->getDateRange($dateRangeInput);
$enabledDrivers = DriverManager::getEnabled();
$missingAutomations = [];
$formattedDrivers = [];
$triggerNames = [];
foreach ($enabledDrivers as $driver) {
$triggerNames[$driver->getTriggerName()] = $driver;
}
$activeTriggers = Funnel::query()
->whereIn('trigger_name', array_keys($triggerNames))
->where('status', 'published')
->pluck('trigger_name')
->unique()
->toArray();
foreach ($enabledDrivers as $driver) {
if (!in_array($driver->getTriggerName(), $activeTriggers, true)) {
// Include the provider slug so the UI can scope the "no automation" notice
// (doc link + starter template differ per provider).
$missingAutomations[] = [
'provider' => $driver->getProviderSlug(),
'label' => $driver->getProviderLabel(),
];
}
$formattedDrivers[$driver->getProviderSlug()] = [
'label' => $driver->getProviderLabel(),
'logo' => $driver->getLogo()
];
}
$carts = AbandonCartModel::orderBy('id', 'DESC')
->with(['subscriber', 'automation']);
if ($dateRange) {
$carts = $carts->whereBetween('created_at', $dateRange);
}
$status = sanitize_text_field(Arr::get($query, 'status', ''));
$search = sanitize_text_field(Arr::get($query, 'search', ''));
$carts = $carts->statusBy($status)
->searchBy($search)
->paginate();
return [
'carts' => $this->mutateCartData($carts),
'haveAutomation' => empty($missingAutomations),
'missingAutomations' => $missingAutomations,
'drivers' => $formattedDrivers
];
}
public function mutateCartData($carts)
{
$updatedData = $carts->getCollection()->transform(function ($cart) {
if ($cart->status == 'processing') {
$cart->recovery_url = $cart->getRecoveryUrl();
}
$subscriber = $cart->subscriber;
// Customer Avatar
$cart->customer_avatar = $subscriber ? $subscriber->photo : fluentcrmGravatar($cart->email, $cart->full_name);
// Driver-specific enrichment (product images, order URL, etc.)
$driver = DriverManager::getDriver($cart->provider);
if ($driver) {
$cart = $driver->enrichCartForListing($cart);
}
// Remove subscriber to clean up output
unset($cart->subscriber);
return $cart;
});
$carts->setCollection(
$updatedData
);
return $carts;
}
public function handleBulkDeleteCart(Request $request)
{
$cartIds = $request->get('cart_ids', []);
if (!$cartIds || !is_array($cartIds)) {
return $this->sendError([
'message' => __('No carts selected to delete', 'fluent-crm')
]);
}
$cartIds = array_map('intval', $cartIds);
$carts = AbandonCartModel::whereIn('id', $cartIds)->get();
foreach ($carts as $cart) {
$cart->deleteCart();
}
return [
'message' => __('Selected carts have been deleted successfully', 'fluent-crm')
];
}
public function getReportSummary(Request $request)
{
$dateRangeInput = $request->get('date_range', []);
$dateRange = $this->getDateRange($dateRangeInput);
[$recoveredCount, $recoveredRevenue] = AbCartHelper::getCountAndSumByStatus('recovered', $dateRange, 'recovered_at');
[$processingCount, $processingRevenue] = AbCartHelper::getCountAndSumByStatus('processing', $dateRange);
[$lostCount, $lostRevenue] = AbCartHelper::getCountAndSumByStatus('lost', $dateRange);
[$draftCount, $draftRevenue] = AbCartHelper::getCountAndSumByStatus('draft', $dateRange);
[$optoutCount, $optoutRevenue] = AbCartHelper::getCountAndSumByStatus('opt_out', $dateRange);
$recoveryRate = '0%';
if ($lostCount) {
$recoveryRate = number_format(($recoveredCount / ($lostCount + $recoveredCount)) * 100, 2) . '%';
} else if ($recoveredCount) {
$recoveryRate = '100%';
}
return [
'widgets' => [
'recovered_revenue' => [
'title' => esc_html__('Recovered Revenue', 'fluent-crm'),
'value' => DriverManager::formatPrice($recoveredRevenue),
'count' => number_format($recoveredCount),
],
'processing_revenue' => [
'title' => esc_html__('Processing Revenue', 'fluent-crm'),
'value' => DriverManager::formatPrice($processingRevenue),
'count' => number_format($processingCount),
],
'lost_revenue' => [
'title' => esc_html__('Lost Revenue', 'fluent-crm'),
'value' => DriverManager::formatPrice($lostRevenue),
'count' => number_format($lostCount),
],
'draft_revenue' => [
'title' => esc_html__('Draft Revenue', 'fluent-crm'),
'value' => DriverManager::formatPrice($draftRevenue),
'count' => number_format($draftCount)
],
'optout_revenue' => [
'title' => esc_html__('Optout Revenue', 'fluent-crm'),
'value' => DriverManager::formatPrice($optoutRevenue),
'count' => number_format($optoutCount)
],
'recovery_rate' => [
'title' => esc_html__('Recovery Rate', 'fluent-crm'),
'value' => $recoveryRate,
'count' => ''
]
]
];
}
public function getDateRange($dateRangeInput)
{
if ($dateRangeInput) {
$dateRange = array_filter($dateRangeInput);
$startTime = isset($dateRange[0]) ? strtotime($dateRange[0]) : false;
$endTime = isset($dateRange[1]) ? strtotime($dateRange[1]) : false;
if (count($dateRange) != 2 || !$startTime || !$endTime || $startTime > $endTime) {
// Invalid date range, fallback to last 30 days
$startDate = gmdate('Y-m-d 00:00:01', strtotime('-30 days'));
$endDate = gmdate('Y-m-d 23:59:59');
$dateRange = [$startDate, $endDate];
} else {
$startDateString = $dateRange[0];
$endDateString = $dateRange[1];
// Remove timezone identifiers
$startDateString = preg_replace('/\(.*\)/', '', $startDateString);
$endDateString = preg_replace('/\(.*\)/', '', $endDateString);
try {
// Parse dates
$startDate = new \DateTime($startDateString);
$endDate = new \DateTime($endDateString);
// Adjust times for range
$startDate->setTime(0, 0, 1); // Set time to 00:00:01
$endDate->setTime(23, 59, 59); // Set time to 23:59:59
// Format for SQL or other usage
$dateRange = [
$startDate->format("Y-m-d H:i:s"),
$endDate->format("Y-m-d H:i:s")
];
} catch (\Exception $e) {
// Fallback to last 30 days
$dateRange = [
gmdate('Y-m-d 00:00:01', strtotime('-30 days')),
gmdate('Y-m-d 23:59:59')
];
}
}
} else {
// Default to last 30 days if no date range provided
$startDate = gmdate('Y-m-d 00:00:01', strtotime('-30 days'));
$endDate = gmdate('Y-m-d 23:59:59');
$dateRange = [$startDate, $endDate];
}
return $dateRange;
}
}