Initial commit
This commit is contained in:
@@ -0,0 +1,236 @@
|
||||
<?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;
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user