add: full multi-tenancy control
This commit is contained in:
@@ -0,0 +1,343 @@
|
||||
<?php
|
||||
|
||||
namespace Webkul\Admin\Helpers\Reporting;
|
||||
|
||||
use Carbon\CarbonPeriod;
|
||||
use Illuminate\Support\Carbon;
|
||||
use Illuminate\Support\Str;
|
||||
|
||||
abstract class AbstractReporting
|
||||
{
|
||||
/**
|
||||
* The starting date for a given period.
|
||||
*/
|
||||
protected Carbon $startDate;
|
||||
|
||||
/**
|
||||
* The ending date for a given period.
|
||||
*/
|
||||
protected Carbon $endDate;
|
||||
|
||||
/**
|
||||
* The starting date for the previous period.
|
||||
*/
|
||||
protected Carbon $lastStartDate;
|
||||
|
||||
/**
|
||||
* The ending date for the previous period.
|
||||
*/
|
||||
protected Carbon $lastEndDate;
|
||||
|
||||
/**
|
||||
* Create a helper instance.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
$this->setStartDate(request()->date('start'));
|
||||
|
||||
$this->setEndDate(request()->date('end'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the start date or default to 30 days ago if not provided.
|
||||
*
|
||||
* @param \Carbon\Carbon|null $startDate
|
||||
* @return void
|
||||
*/
|
||||
public function setStartDate(?Carbon $startDate = null): self
|
||||
{
|
||||
$this->startDate = $startDate ? $startDate->startOfDay() : now()->subDays(30)->startOfDay();
|
||||
|
||||
$this->setLastStartDate();
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the end date to the provided date's end of day, or to the current
|
||||
* date if not provided or if the provided date is in the future.
|
||||
*
|
||||
* @param \Carbon\Carbon|null $endDate
|
||||
* @return void
|
||||
*/
|
||||
public function setEndDate(?Carbon $endDate = null): self
|
||||
{
|
||||
$this->endDate = ($endDate && $endDate->endOfDay() <= now()) ? $endDate->endOfDay() : now();
|
||||
|
||||
$this->setLastEndDate();
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the start date.
|
||||
*
|
||||
* @return \Carbon\Carbon
|
||||
*/
|
||||
public function getStartDate(): Carbon
|
||||
{
|
||||
return $this->startDate;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the end date.
|
||||
*
|
||||
* @return \Carbon\Carbon
|
||||
*/
|
||||
public function getEndDate(): Carbon
|
||||
{
|
||||
return $this->endDate;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the start date for the last period.
|
||||
*/
|
||||
private function setLastStartDate(): void
|
||||
{
|
||||
if (! isset($this->startDate)) {
|
||||
$this->setStartDate(request()->date('start'));
|
||||
}
|
||||
|
||||
if (! isset($this->endDate)) {
|
||||
$this->setEndDate(request()->date('end'));
|
||||
}
|
||||
|
||||
$this->lastStartDate = $this->startDate->clone()->subDays($this->startDate->diffInDays($this->endDate));
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the end date for the last period.
|
||||
*/
|
||||
private function setLastEndDate(): void
|
||||
{
|
||||
$this->lastEndDate = $this->startDate->clone();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the last start date.
|
||||
*
|
||||
* @return \Carbon\Carbon
|
||||
*/
|
||||
public function getLastStartDate(): Carbon
|
||||
{
|
||||
return $this->lastStartDate;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the last end date.
|
||||
*
|
||||
* @return \Carbon\Carbon
|
||||
*/
|
||||
public function getLastEndDate(): Carbon
|
||||
{
|
||||
return $this->lastEndDate;
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculate the percentage change between previous and current values.
|
||||
*
|
||||
* @param float|int $previous
|
||||
* @param float|int $current
|
||||
*/
|
||||
public function getPercentageChange($previous, $current): float|int
|
||||
{
|
||||
if (! $previous) {
|
||||
return $current ? 100 : 0;
|
||||
}
|
||||
|
||||
return ($current - $previous) / $previous * 100;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns time intervals.
|
||||
*
|
||||
* @param \Carbon\Carbon $startDate
|
||||
* @param \Carbon\Carbon $endDate
|
||||
* @param string $period
|
||||
* @return array
|
||||
*/
|
||||
public function getTimeInterval($startDate, $endDate, $dateColumn, $period)
|
||||
{
|
||||
if ($period == 'auto') {
|
||||
$totalMonths = $startDate->diffInMonths($endDate) + 1;
|
||||
|
||||
/**
|
||||
* If the difference between the start and end date is more than 5 months
|
||||
*/
|
||||
$intervals = $this->getMonthsInterval($startDate, $endDate);
|
||||
|
||||
if (! empty($intervals)) {
|
||||
return [
|
||||
'group_column' => "MONTH($dateColumn)",
|
||||
'intervals' => $intervals,
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* If the difference between the start and end date is more than 6 weeks
|
||||
*/
|
||||
$intervals = $this->getWeeksInterval($startDate, $endDate);
|
||||
|
||||
if (! empty($intervals)) {
|
||||
return [
|
||||
'group_column' => "WEEK($dateColumn)",
|
||||
'intervals' => $intervals,
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* If the difference between the start and end date is less than 6 weeks
|
||||
*/
|
||||
return [
|
||||
'group_column' => "DAYOFYEAR($dateColumn)",
|
||||
'intervals' => $this->getDaysInterval($startDate, $endDate),
|
||||
];
|
||||
} else {
|
||||
$datePeriod = CarbonPeriod::create($this->startDate, "1 $period", $this->endDate);
|
||||
|
||||
if ($period == 'year') {
|
||||
$formatter = '?';
|
||||
} elseif ($period == 'month') {
|
||||
$formatter = '?-?';
|
||||
} else {
|
||||
$formatter = '?-?-?';
|
||||
}
|
||||
|
||||
$groupColumn = 'DATE_FORMAT('.$dateColumn.', "'.Str::replaceArray('?', ['%Y', '%m', '%d'], $formatter).'")';
|
||||
|
||||
$intervals = [];
|
||||
|
||||
foreach ($datePeriod as $date) {
|
||||
$formattedDate = $date->format(Str::replaceArray('?', ['Y', 'm', 'd'], $formatter));
|
||||
|
||||
$intervals[] = [
|
||||
'filter' => $formattedDate,
|
||||
'start' => $formattedDate,
|
||||
];
|
||||
}
|
||||
|
||||
return [
|
||||
'group_column' => $groupColumn,
|
||||
'intervals' => $intervals,
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns time intervals.
|
||||
*
|
||||
* @param \Carbon\Carbon $startDate
|
||||
* @param \Carbon\Carbon $endDate
|
||||
* @return array
|
||||
*/
|
||||
public function getMonthsInterval($startDate, $endDate)
|
||||
{
|
||||
$intervals = [];
|
||||
|
||||
$totalMonths = $startDate->diffInMonths($endDate) + 1;
|
||||
|
||||
/**
|
||||
* If the difference between the start and end date is less than 5 months
|
||||
*/
|
||||
if ($totalMonths <= 5) {
|
||||
return $intervals;
|
||||
}
|
||||
|
||||
for ($i = 0; $i < $totalMonths; $i++) {
|
||||
$intervalStartDate = clone $startDate;
|
||||
|
||||
$intervalStartDate->addMonths($i);
|
||||
|
||||
$start = $intervalStartDate->startOfDay();
|
||||
|
||||
$end = ($totalMonths - 1 == $i)
|
||||
? $endDate
|
||||
: $intervalStartDate->addMonth()->subDay()->endOfDay();
|
||||
|
||||
$intervals[] = [
|
||||
'filter' => $start->month,
|
||||
'start' => $start->format('d M'),
|
||||
'end' => $end->format('d M'),
|
||||
];
|
||||
}
|
||||
|
||||
return $intervals;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns time intervals.
|
||||
*
|
||||
* @param \Carbon\Carbon $startDate
|
||||
* @param \Carbon\Carbon $endDate
|
||||
* @return array
|
||||
*/
|
||||
public function getWeeksInterval($startDate, $endDate)
|
||||
{
|
||||
$intervals = [];
|
||||
|
||||
$startWeekDay = Carbon::createFromTimeString(core()->xWeekRange($startDate, 0).' 00:00:01');
|
||||
|
||||
$endWeekDay = Carbon::createFromTimeString(core()->xWeekRange($endDate, 1).' 23:59:59');
|
||||
|
||||
$totalWeeks = $startWeekDay->diffInWeeks($endWeekDay);
|
||||
|
||||
/**
|
||||
* If the difference between the start and end date is less than 6 weeks
|
||||
*/
|
||||
if ($totalWeeks <= 6) {
|
||||
return $intervals;
|
||||
}
|
||||
|
||||
for ($i = 0; $i < $totalWeeks; $i++) {
|
||||
$intervalStartDate = clone $startDate;
|
||||
|
||||
$intervalStartDate->addWeeks($i);
|
||||
|
||||
$start = $i == 0
|
||||
? $startDate
|
||||
: Carbon::createFromTimeString(core()->xWeekRange($intervalStartDate, 0).' 00:00:01');
|
||||
|
||||
$end = ($totalWeeks - 1 == $i)
|
||||
? $endDate
|
||||
: Carbon::createFromTimeString(core()->xWeekRange($intervalStartDate->subDay(), 1).' 23:59:59');
|
||||
|
||||
$intervals[] = [
|
||||
'filter' => $start->week,
|
||||
'start' => $start->format('d M'),
|
||||
'end' => $end->format('d M'),
|
||||
];
|
||||
}
|
||||
|
||||
return $intervals;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns time intervals.
|
||||
*
|
||||
* @param \Carbon\Carbon $startDate
|
||||
* @param \Carbon\Carbon $endDate
|
||||
* @return array
|
||||
*/
|
||||
public function getDaysInterval($startDate, $endDate)
|
||||
{
|
||||
$intervals = [];
|
||||
|
||||
$totalDays = $startDate->diffInDays($endDate) + 1;
|
||||
|
||||
for ($i = 0; $i < $totalDays; $i++) {
|
||||
$intervalStartDate = clone $startDate;
|
||||
|
||||
$intervalStartDate->addDays($i);
|
||||
|
||||
$intervals[] = [
|
||||
'filter' => $intervalStartDate->dayOfYear,
|
||||
'start' => $intervalStartDate->startOfDay()->format('d M'),
|
||||
'end' => $intervalStartDate->endOfDay()->format('d M'),
|
||||
];
|
||||
}
|
||||
|
||||
return $intervals;
|
||||
}
|
||||
}
|
||||
5
packages/Webkul/Admin/src/Helpers/Reporting/Activity.php
Normal file
5
packages/Webkul/Admin/src/Helpers/Reporting/Activity.php
Normal file
@@ -0,0 +1,5 @@
|
||||
<?php
|
||||
|
||||
namespace Webkul\Admin\Helpers\Reporting;
|
||||
|
||||
class Activity extends AbstractReporting {}
|
||||
483
packages/Webkul/Admin/src/Helpers/Reporting/Lead.php
Normal file
483
packages/Webkul/Admin/src/Helpers/Reporting/Lead.php
Normal file
@@ -0,0 +1,483 @@
|
||||
<?php
|
||||
|
||||
namespace Webkul\Admin\Helpers\Reporting;
|
||||
|
||||
use Carbon\Carbon;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use Webkul\Lead\Repositories\LeadRepository;
|
||||
use Webkul\Lead\Repositories\StageRepository;
|
||||
|
||||
class Lead extends AbstractReporting
|
||||
{
|
||||
/**
|
||||
* The channel ids.
|
||||
*/
|
||||
protected array $stageIds;
|
||||
|
||||
/**
|
||||
* The all stage ids.
|
||||
*/
|
||||
protected array $allStageIds;
|
||||
|
||||
/**
|
||||
* The won stage ids.
|
||||
*/
|
||||
protected array $wonStageIds;
|
||||
|
||||
/**
|
||||
* The lost stage ids.
|
||||
*/
|
||||
protected array $lostStageIds;
|
||||
|
||||
/**
|
||||
* Create a helper instance.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function __construct(
|
||||
protected LeadRepository $leadRepository,
|
||||
protected StageRepository $stageRepository
|
||||
) {
|
||||
$this->allStageIds = $this->stageRepository->pluck('id')->toArray();
|
||||
|
||||
$this->wonStageIds = $this->stageRepository->where('code', 'won')->pluck('id')->toArray();
|
||||
|
||||
$this->lostStageIds = $this->stageRepository->where('code', 'lost')->pluck('id')->toArray();
|
||||
|
||||
parent::__construct();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns current customers over time
|
||||
*
|
||||
* @param string $period
|
||||
*/
|
||||
public function getTotalLeadsOverTime($period = 'auto'): array
|
||||
{
|
||||
$this->stageIds = $this->allStageIds;
|
||||
|
||||
$period = $this->determinePeriod($period);
|
||||
|
||||
return $this->getOverTimeStats($this->startDate, $this->endDate, 'leads.id', 'created_at', $period);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns current customers over time
|
||||
*
|
||||
* @param string $period
|
||||
*/
|
||||
public function getTotalWonLeadsOverTime($period = 'auto'): array
|
||||
{
|
||||
$this->stageIds = $this->wonStageIds;
|
||||
|
||||
$period = $this->determinePeriod($period);
|
||||
|
||||
return $this->getOverTimeStats($this->startDate, $this->endDate, 'leads.id', 'closed_at', $period);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns current customers over time
|
||||
*
|
||||
* @param string $period
|
||||
*/
|
||||
public function getTotalLostLeadsOverTime($period = 'auto'): array
|
||||
{
|
||||
$this->stageIds = $this->lostStageIds;
|
||||
|
||||
$period = $this->determinePeriod($period);
|
||||
|
||||
return $this->getOverTimeStats($this->startDate, $this->endDate, 'leads.id', 'closed_at', $period);
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine the appropriate period based on date range
|
||||
*
|
||||
* @param string $period
|
||||
*/
|
||||
protected function determinePeriod($period = 'auto'): string
|
||||
{
|
||||
if ($period !== 'auto') {
|
||||
return $period;
|
||||
}
|
||||
|
||||
$diffInDays = $this->startDate->diffInDays($this->endDate);
|
||||
$diffInMonths = $this->startDate->diffInMonths($this->endDate);
|
||||
$diffInYears = $this->startDate->diffInYears($this->endDate);
|
||||
|
||||
if ($diffInYears > 3) {
|
||||
return 'year';
|
||||
} elseif ($diffInMonths > 6) {
|
||||
return 'month';
|
||||
} elseif ($diffInDays > 60) {
|
||||
return 'week';
|
||||
} else {
|
||||
return 'day';
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves total leads and their progress.
|
||||
*/
|
||||
public function getTotalLeadsProgress(): array
|
||||
{
|
||||
return [
|
||||
'previous' => $previous = $this->getTotalLeads($this->lastStartDate, $this->lastEndDate),
|
||||
'current' => $current = $this->getTotalLeads($this->startDate, $this->endDate),
|
||||
'progress' => $this->getPercentageChange($previous, $current),
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves total leads by date
|
||||
*
|
||||
* @param \Carbon\Carbon $startDate
|
||||
* @param \Carbon\Carbon $endDate
|
||||
*/
|
||||
public function getTotalLeads($startDate, $endDate): int
|
||||
{
|
||||
return $this->leadRepository
|
||||
->resetModel()
|
||||
->whereBetween('created_at', [$startDate, $endDate])
|
||||
->count();
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves average leads per day and their progress.
|
||||
*/
|
||||
public function getAverageLeadsPerDayProgress(): array
|
||||
{
|
||||
return [
|
||||
'previous' => $previous = $this->getAverageLeadsPerDay($this->lastStartDate, $this->lastEndDate),
|
||||
'current' => $current = $this->getAverageLeadsPerDay($this->startDate, $this->endDate),
|
||||
'progress' => $this->getPercentageChange($previous, $current),
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves average leads per day
|
||||
*
|
||||
* @param \Carbon\Carbon $startDate
|
||||
* @param \Carbon\Carbon $endDate
|
||||
*/
|
||||
public function getAverageLeadsPerDay($startDate, $endDate): float
|
||||
{
|
||||
$days = $startDate->diffInDays($endDate);
|
||||
|
||||
if ($days == 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return $this->getTotalLeads($startDate, $endDate) / $days;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves total lead value and their progress.
|
||||
*/
|
||||
public function getTotalLeadValueProgress(): array
|
||||
{
|
||||
return [
|
||||
'previous' => $previous = $this->getTotalLeadValue($this->lastStartDate, $this->lastEndDate),
|
||||
'current' => $current = $this->getTotalLeadValue($this->startDate, $this->endDate),
|
||||
'formatted_total' => core()->formatBasePrice($current),
|
||||
'progress' => $this->getPercentageChange($previous, $current),
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves total lead value
|
||||
*
|
||||
* @param \Carbon\Carbon $startDate
|
||||
* @param \Carbon\Carbon $endDate
|
||||
*/
|
||||
public function getTotalLeadValue($startDate, $endDate): float
|
||||
{
|
||||
return $this->leadRepository
|
||||
->resetModel()
|
||||
->whereBetween('created_at', [$startDate, $endDate])
|
||||
->sum('lead_value');
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves average lead value and their progress.
|
||||
*/
|
||||
public function getAverageLeadValueProgress(): array
|
||||
{
|
||||
return [
|
||||
'previous' => $previous = $this->getAverageLeadValue($this->lastStartDate, $this->lastEndDate),
|
||||
'current' => $current = $this->getAverageLeadValue($this->startDate, $this->endDate),
|
||||
'formatted_total' => core()->formatBasePrice($current),
|
||||
'progress' => $this->getPercentageChange($previous, $current),
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves average lead value
|
||||
*
|
||||
* @param \Carbon\Carbon $startDate
|
||||
* @param \Carbon\Carbon $endDate
|
||||
*/
|
||||
public function getAverageLeadValue($startDate, $endDate): float
|
||||
{
|
||||
return $this->leadRepository
|
||||
->resetModel()
|
||||
->whereBetween('created_at', [$startDate, $endDate])
|
||||
->avg('lead_value') ?? 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves total won lead value and their progress.
|
||||
*/
|
||||
public function getTotalWonLeadValueProgress(): array
|
||||
{
|
||||
return [
|
||||
'previous' => $previous = $this->getTotalWonLeadValue($this->lastStartDate, $this->lastEndDate),
|
||||
'current' => $current = $this->getTotalWonLeadValue($this->startDate, $this->endDate),
|
||||
'formatted_total' => core()->formatBasePrice($current),
|
||||
'progress' => $this->getPercentageChange($previous, $current),
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves average won lead value
|
||||
*
|
||||
* @param \Carbon\Carbon $startDate
|
||||
* @param \Carbon\Carbon $endDate
|
||||
* @return array
|
||||
*/
|
||||
public function getTotalWonLeadValue($startDate, $endDate): ?float
|
||||
{
|
||||
return $this->leadRepository
|
||||
->resetModel()
|
||||
->whereIn('lead_pipeline_stage_id', $this->wonStageIds)
|
||||
->whereBetween('created_at', [$startDate, $endDate])
|
||||
->sum('lead_value');
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves average lost lead value and their progress.
|
||||
*/
|
||||
public function getTotalLostLeadValueProgress(): array
|
||||
{
|
||||
return [
|
||||
'previous' => $previous = $this->getTotalLostLeadValue($this->lastStartDate, $this->lastEndDate),
|
||||
'current' => $current = $this->getTotalLostLeadValue($this->startDate, $this->endDate),
|
||||
'formatted_total' => core()->formatBasePrice($current),
|
||||
'progress' => $this->getPercentageChange($previous, $current),
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves average lost lead value
|
||||
*
|
||||
* @param \Carbon\Carbon $startDate
|
||||
* @param \Carbon\Carbon $endDate
|
||||
* @return array
|
||||
*/
|
||||
public function getTotalLostLeadValue($startDate, $endDate): ?float
|
||||
{
|
||||
return $this->leadRepository
|
||||
->resetModel()
|
||||
->whereIn('lead_pipeline_stage_id', $this->lostStageIds)
|
||||
->whereBetween('created_at', [$startDate, $endDate])
|
||||
->sum('lead_value');
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves total lead value by sources.
|
||||
*/
|
||||
public function getTotalWonLeadValueBySources()
|
||||
{
|
||||
return $this->leadRepository
|
||||
->resetModel()
|
||||
->select(
|
||||
'lead_sources.name',
|
||||
DB::raw('SUM(lead_value) as total')
|
||||
)
|
||||
->leftJoin('lead_sources', 'leads.lead_source_id', '=', 'lead_sources.id')
|
||||
->whereIn('lead_pipeline_stage_id', $this->wonStageIds)
|
||||
->whereBetween('leads.created_at', [$this->startDate, $this->endDate])
|
||||
->groupBy('lead_source_id')
|
||||
->get();
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves total lead value by types.
|
||||
*/
|
||||
public function getTotalWonLeadValueByTypes()
|
||||
{
|
||||
return $this->leadRepository
|
||||
->resetModel()
|
||||
->select(
|
||||
'lead_types.name',
|
||||
DB::raw('SUM(lead_value) as total')
|
||||
)
|
||||
->leftJoin('lead_types', 'leads.lead_type_id', '=', 'lead_types.id')
|
||||
->whereIn('lead_pipeline_stage_id', $this->wonStageIds)
|
||||
->whereBetween('leads.created_at', [$this->startDate, $this->endDate])
|
||||
->groupBy('lead_type_id')
|
||||
->get();
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves open leads by states.
|
||||
*/
|
||||
public function getOpenLeadsByStates()
|
||||
{
|
||||
return $this->leadRepository
|
||||
->resetModel()
|
||||
->select(
|
||||
'lead_pipeline_stages.name',
|
||||
DB::raw('COUNT(lead_value) as total')
|
||||
)
|
||||
->leftJoin('lead_pipeline_stages', 'leads.lead_pipeline_stage_id', '=', 'lead_pipeline_stages.id')
|
||||
->whereNotIn('lead_pipeline_stage_id', $this->wonStageIds)
|
||||
->whereNotIn('lead_pipeline_stage_id', $this->lostStageIds)
|
||||
->whereBetween('leads.created_at', [$this->startDate, $this->endDate])
|
||||
->groupBy('lead_pipeline_stage_id')
|
||||
->orderByDesc('total')
|
||||
->get();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns over time stats.
|
||||
*
|
||||
* @param \Carbon\Carbon $startDate
|
||||
* @param \Carbon\Carbon $endDate
|
||||
* @param string $valueColumn
|
||||
* @param string $dateColumn
|
||||
* @param string $period
|
||||
*/
|
||||
public function getOverTimeStats($startDate, $endDate, $valueColumn, $dateColumn = 'created_at', $period = 'auto'): array
|
||||
{
|
||||
$period = $this->determinePeriod($period);
|
||||
|
||||
$intervals = $this->generateTimeIntervals($startDate, $endDate, $period);
|
||||
|
||||
$groupColumn = $this->getGroupColumn($dateColumn, $period);
|
||||
|
||||
$query = $this->leadRepository
|
||||
->resetModel()
|
||||
->select(
|
||||
DB::raw("$groupColumn AS date"),
|
||||
DB::raw('COUNT(DISTINCT id) AS count'),
|
||||
DB::raw('SUM('.\DB::getTablePrefix()."$valueColumn) AS total")
|
||||
)
|
||||
->whereIn('lead_pipeline_stage_id', $this->stageIds)
|
||||
->whereBetween($dateColumn, [$startDate, $endDate])
|
||||
->groupBy(DB::raw($groupColumn))
|
||||
->orderBy(DB::raw($groupColumn));
|
||||
|
||||
$results = $query->get();
|
||||
$resultLookup = $results->keyBy('date');
|
||||
|
||||
$stats = [];
|
||||
|
||||
foreach ($intervals as $interval) {
|
||||
$result = $resultLookup->get($interval['key']);
|
||||
|
||||
$stats[] = [
|
||||
'label' => $interval['label'],
|
||||
'count' => $result ? (int) $result->count : 0,
|
||||
'total' => $result ? (float) $result->total : 0,
|
||||
];
|
||||
}
|
||||
|
||||
return $stats;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate time intervals based on period
|
||||
*/
|
||||
protected function generateTimeIntervals(Carbon $startDate, Carbon $endDate, string $period): array
|
||||
{
|
||||
$intervals = [];
|
||||
$current = $startDate->copy();
|
||||
|
||||
while ($current <= $endDate) {
|
||||
$interval = [
|
||||
'key' => $this->formatDateForGrouping($current, $period),
|
||||
'label' => $this->formatDateForLabel($current, $period),
|
||||
];
|
||||
|
||||
$intervals[] = $interval;
|
||||
|
||||
switch ($period) {
|
||||
case 'day':
|
||||
$current->addDay();
|
||||
|
||||
break;
|
||||
case 'week':
|
||||
$current->addWeek();
|
||||
|
||||
break;
|
||||
case 'month':
|
||||
$current->addMonth();
|
||||
|
||||
break;
|
||||
case 'year':
|
||||
$current->addYear();
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return $intervals;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the SQL group column based on period
|
||||
*/
|
||||
protected function getGroupColumn(string $dateColumn, string $period): string
|
||||
{
|
||||
switch ($period) {
|
||||
case 'day':
|
||||
return "DATE($dateColumn)";
|
||||
case 'week':
|
||||
return "DATE_FORMAT($dateColumn, '%Y-%u')";
|
||||
case 'month':
|
||||
return "DATE_FORMAT($dateColumn, '%Y-%m')";
|
||||
case 'year':
|
||||
return "YEAR($dateColumn)";
|
||||
default:
|
||||
return "DATE($dateColumn)";
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Format date for grouping key
|
||||
*/
|
||||
protected function formatDateForGrouping(Carbon $date, string $period): string
|
||||
{
|
||||
switch ($period) {
|
||||
case 'day':
|
||||
return $date->format('Y-m-d');
|
||||
case 'week':
|
||||
return $date->format('Y-W');
|
||||
case 'month':
|
||||
return $date->format('Y-m');
|
||||
case 'year':
|
||||
return $date->format('Y');
|
||||
default:
|
||||
return $date->format('Y-m-d');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Format date for display label
|
||||
*/
|
||||
protected function formatDateForLabel(Carbon $date, string $period): string
|
||||
{
|
||||
switch ($period) {
|
||||
case 'day':
|
||||
return $date->format('M d');
|
||||
case 'week':
|
||||
return 'Week '.$date->format('W, Y');
|
||||
case 'month':
|
||||
return $date->format('M Y');
|
||||
case 'year':
|
||||
return $date->format('Y');
|
||||
default:
|
||||
return $date->format('M d');
|
||||
}
|
||||
}
|
||||
}
|
||||
80
packages/Webkul/Admin/src/Helpers/Reporting/Organization.php
Normal file
80
packages/Webkul/Admin/src/Helpers/Reporting/Organization.php
Normal file
@@ -0,0 +1,80 @@
|
||||
<?php
|
||||
|
||||
namespace Webkul\Admin\Helpers\Reporting;
|
||||
|
||||
use Illuminate\Support\Collection;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use Webkul\Contact\Repositories\OrganizationRepository;
|
||||
|
||||
class Organization extends AbstractReporting
|
||||
{
|
||||
/**
|
||||
* Create a helper instance.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function __construct(protected OrganizationRepository $organizationRepository)
|
||||
{
|
||||
parent::__construct();
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves total organizations and their progress.
|
||||
*/
|
||||
public function getTotalOrganizationsProgress(): array
|
||||
{
|
||||
return [
|
||||
'previous' => $previous = $this->getTotalOrganizations($this->lastStartDate, $this->lastEndDate),
|
||||
'current' => $current = $this->getTotalOrganizations($this->startDate, $this->endDate),
|
||||
'progress' => $this->getPercentageChange($previous, $current),
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves total organizations by date
|
||||
*
|
||||
* @param \Carbon\Carbon $startDate
|
||||
* @param \Carbon\Carbon $endDate
|
||||
*/
|
||||
public function getTotalOrganizations($startDate, $endDate): int
|
||||
{
|
||||
return $this->organizationRepository
|
||||
->resetModel()
|
||||
->whereBetween('created_at', [$startDate, $endDate])
|
||||
->count();
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets top customers by revenue.
|
||||
*
|
||||
* @param int $limit
|
||||
*/
|
||||
public function getTopOrganizationsByRevenue($limit = null): Collection
|
||||
{
|
||||
$tablePrefix = DB::getTablePrefix();
|
||||
|
||||
$items = $this->organizationRepository
|
||||
->resetModel()
|
||||
->leftJoin('persons', 'organizations.id', '=', 'persons.organization_id')
|
||||
->leftJoin('leads', 'persons.id', '=', 'leads.person_id')
|
||||
->select('*', 'persons.id as id')
|
||||
->addSelect(DB::raw('SUM('.$tablePrefix.'leads.lead_value) as revenue'))
|
||||
->whereBetween('leads.closed_at', [$this->startDate, $this->endDate])
|
||||
->having(DB::raw('SUM('.$tablePrefix.'leads.lead_value)'), '>', 0)
|
||||
->groupBy('organization_id')
|
||||
->orderBy('revenue', 'DESC')
|
||||
->limit($limit)
|
||||
->get();
|
||||
|
||||
$items = $items->map(function ($item) {
|
||||
return [
|
||||
'id' => $item->id,
|
||||
'name' => $item->name,
|
||||
'revenue' => $item->revenue,
|
||||
'formatted_revenue' => core()->formatBasePrice($item->revenue),
|
||||
];
|
||||
});
|
||||
|
||||
return $items;
|
||||
}
|
||||
}
|
||||
81
packages/Webkul/Admin/src/Helpers/Reporting/Person.php
Normal file
81
packages/Webkul/Admin/src/Helpers/Reporting/Person.php
Normal file
@@ -0,0 +1,81 @@
|
||||
<?php
|
||||
|
||||
namespace Webkul\Admin\Helpers\Reporting;
|
||||
|
||||
use Illuminate\Support\Collection;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use Webkul\Contact\Repositories\PersonRepository;
|
||||
|
||||
class Person extends AbstractReporting
|
||||
{
|
||||
/**
|
||||
* Create a helper instance.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function __construct(protected PersonRepository $personRepository)
|
||||
{
|
||||
parent::__construct();
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves total persons and their progress.
|
||||
*/
|
||||
public function getTotalPersonsProgress(): array
|
||||
{
|
||||
return [
|
||||
'previous' => $previous = $this->getTotalPersons($this->lastStartDate, $this->lastEndDate),
|
||||
'current' => $current = $this->getTotalPersons($this->startDate, $this->endDate),
|
||||
'progress' => $this->getPercentageChange($previous, $current),
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves total persons by date
|
||||
*
|
||||
* @param \Carbon\Carbon $startDate
|
||||
* @param \Carbon\Carbon $endDate
|
||||
*/
|
||||
public function getTotalPersons($startDate, $endDate): int
|
||||
{
|
||||
return $this->personRepository
|
||||
->resetModel()
|
||||
->whereBetween('created_at', [$startDate, $endDate])
|
||||
->count();
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets top customers by revenue.
|
||||
*
|
||||
* @param int $limit
|
||||
*/
|
||||
public function getTopCustomersByRevenue($limit = null): Collection
|
||||
{
|
||||
$tablePrefix = DB::getTablePrefix();
|
||||
|
||||
$items = $this->personRepository
|
||||
->resetModel()
|
||||
->leftJoin('leads', 'persons.id', '=', 'leads.person_id')
|
||||
->select('*', 'persons.id as id')
|
||||
->addSelect(DB::raw('SUM('.$tablePrefix.'leads.lead_value) as revenue'))
|
||||
->whereBetween('leads.closed_at', [$this->startDate, $this->endDate])
|
||||
->having(DB::raw('SUM('.$tablePrefix.'leads.lead_value)'), '>', 0)
|
||||
->groupBy('person_id')
|
||||
->orderBy('revenue', 'DESC')
|
||||
->limit($limit)
|
||||
->get();
|
||||
|
||||
$items = $items->map(function ($item) {
|
||||
return [
|
||||
'id' => $item->id,
|
||||
'name' => $item->name,
|
||||
'emails' => $item->emails,
|
||||
'contact_numbers' => $item->contact_numbers,
|
||||
'revenue' => $item->revenue,
|
||||
'formatted_revenue' => core()->formatBasePrice($item->revenue),
|
||||
];
|
||||
});
|
||||
|
||||
return $items;
|
||||
}
|
||||
}
|
||||
94
packages/Webkul/Admin/src/Helpers/Reporting/Product.php
Normal file
94
packages/Webkul/Admin/src/Helpers/Reporting/Product.php
Normal file
@@ -0,0 +1,94 @@
|
||||
<?php
|
||||
|
||||
namespace Webkul\Admin\Helpers\Reporting;
|
||||
|
||||
use Illuminate\Support\Collection;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use Webkul\Lead\Repositories\ProductRepository;
|
||||
|
||||
class Product extends AbstractReporting
|
||||
{
|
||||
/**
|
||||
* Create a helper instance.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function __construct(
|
||||
protected ProductRepository $productRepository
|
||||
) {
|
||||
parent::__construct();
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets top-selling products by revenue.
|
||||
*
|
||||
* @param int $limit
|
||||
*/
|
||||
public function getTopSellingProductsByRevenue($limit = null): Collection
|
||||
{
|
||||
$tablePrefix = DB::getTablePrefix();
|
||||
|
||||
$items = $this->productRepository
|
||||
->resetModel()
|
||||
->with('product')
|
||||
->leftJoin('leads', 'lead_products.lead_id', '=', 'leads.id')
|
||||
->leftJoin('products', 'lead_products.product_id', '=', 'products.id')
|
||||
->select('*')
|
||||
->addSelect(DB::raw('SUM('.$tablePrefix.'lead_products.amount) as revenue'))
|
||||
->whereBetween('leads.closed_at', [$this->startDate, $this->endDate])
|
||||
->having(DB::raw('SUM('.$tablePrefix.'lead_products.amount)'), '>', 0)
|
||||
->groupBy('product_id')
|
||||
->orderBy('revenue', 'DESC')
|
||||
->limit($limit)
|
||||
->get();
|
||||
|
||||
$items = $items->map(function ($item) {
|
||||
return [
|
||||
'id' => $item->product_id,
|
||||
'name' => $item->name,
|
||||
'price' => $item->product?->price,
|
||||
'formatted_price' => core()->formatBasePrice($item->price),
|
||||
'revenue' => $item->revenue,
|
||||
'formatted_revenue' => core()->formatBasePrice($item->revenue),
|
||||
];
|
||||
});
|
||||
|
||||
return $items;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets top-selling products by quantity.
|
||||
*
|
||||
* @param int $limit
|
||||
*/
|
||||
public function getTopSellingProductsByQuantity($limit = null): Collection
|
||||
{
|
||||
$tablePrefix = DB::getTablePrefix();
|
||||
|
||||
$items = $this->productRepository
|
||||
->resetModel()
|
||||
->with('product')
|
||||
->leftJoin('leads', 'lead_products.lead_id', '=', 'leads.id')
|
||||
->leftJoin('products', 'lead_products.product_id', '=', 'products.id')
|
||||
->select('*')
|
||||
->addSelect(DB::raw('SUM('.$tablePrefix.'lead_products.quantity) as total_qty_ordered'))
|
||||
->whereBetween('leads.closed_at', [$this->startDate, $this->endDate])
|
||||
->having(DB::raw('SUM('.$tablePrefix.'lead_products.quantity)'), '>', 0)
|
||||
->groupBy('product_id')
|
||||
->orderBy('total_qty_ordered', 'DESC')
|
||||
->limit($limit)
|
||||
->get();
|
||||
|
||||
$items = $items->map(function ($item) {
|
||||
return [
|
||||
'id' => $item->product_id,
|
||||
'name' => $item->name,
|
||||
'price' => $item->product?->price,
|
||||
'formatted_price' => core()->formatBasePrice($item->price),
|
||||
'total_qty_ordered' => $item->total_qty_ordered,
|
||||
];
|
||||
});
|
||||
|
||||
return $items;
|
||||
}
|
||||
}
|
||||
44
packages/Webkul/Admin/src/Helpers/Reporting/Quote.php
Normal file
44
packages/Webkul/Admin/src/Helpers/Reporting/Quote.php
Normal file
@@ -0,0 +1,44 @@
|
||||
<?php
|
||||
|
||||
namespace Webkul\Admin\Helpers\Reporting;
|
||||
|
||||
use Webkul\Quote\Repositories\QuoteRepository;
|
||||
|
||||
class Quote extends AbstractReporting
|
||||
{
|
||||
/**
|
||||
* Create a helper instance.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function __construct(protected QuoteRepository $quoteRepository)
|
||||
{
|
||||
parent::__construct();
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves total quotes and their progress.
|
||||
*/
|
||||
public function getTotalQuotesProgress(): array
|
||||
{
|
||||
return [
|
||||
'previous' => $previous = $this->getTotalQuotes($this->lastStartDate, $this->lastEndDate),
|
||||
'current' => $current = $this->getTotalQuotes($this->startDate, $this->endDate),
|
||||
'progress' => $this->getPercentageChange($previous, $current),
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves total quotes by date
|
||||
*
|
||||
* @param \Carbon\Carbon $startDate
|
||||
* @param \Carbon\Carbon $endDate
|
||||
*/
|
||||
public function getTotalQuotes($startDate, $endDate): int
|
||||
{
|
||||
return $this->quoteRepository
|
||||
->resetModel()
|
||||
->whereBetween('created_at', [$startDate, $endDate])
|
||||
->count();
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user