329 lines
12 KiB
PHP
329 lines
12 KiB
PHP
<?php
|
|
|
|
declare(strict_types=1);
|
|
|
|
namespace App\Services;
|
|
|
|
use App\Contracts\Directories\EmployeeDirectory;
|
|
use App\Contracts\Directories\OrderDirectory;
|
|
use Carbon\CarbonInterface;
|
|
use Carbon\CarbonPeriod;
|
|
use Domain\Enums\OrderStatus;
|
|
use Domain\Enums\StatsCustomerType;
|
|
use Domain\Enums\StatsShopType;
|
|
use Illuminate\Support\Collection;
|
|
|
|
class StatsService
|
|
{
|
|
public function __construct(
|
|
private readonly EmployeeDirectory $employeeDirectory,
|
|
private readonly OrderDirectory $orderDirectory
|
|
) {
|
|
}
|
|
|
|
/**
|
|
* getStats
|
|
*
|
|
* @param array<int, \Domain\Enums\StatsCustomerType|\Domain\Enums\StatsShopType> $statsType
|
|
* @return array<int, array{previous:int|float,current:int|float,diff:int|float}>
|
|
*
|
|
* @phpcs:disable Generic.Metrics.CyclomaticComplexity
|
|
*/
|
|
public function getStats(array $statsType, CarbonInterface $start, CarbonInterface $end): array
|
|
{
|
|
// phpcs:enable
|
|
$stats = [];
|
|
foreach ($statsType as $type) {
|
|
$previousPeriod = $this->getPreviousPeriod($start, $end);
|
|
$previousStart = $previousPeriod->getStartDate();
|
|
$previousEnd = $previousPeriod->getIncludedEndDate();
|
|
|
|
switch ($type) {
|
|
case StatsShopType::canceledRate:
|
|
$previous = $this->getCanceledRate($previousStart, $previousEnd);
|
|
$current = $this->getCanceledRate($start, $end);
|
|
break;
|
|
case StatsShopType::orderFrequency:
|
|
$previous = $this->getOrderFrequency($previousStart, $previousEnd);
|
|
$current = $this->getOrderFrequency($start, $end);
|
|
break;
|
|
case StatsShopType::purchaseFrequency:
|
|
$previous = $this->getPurchaseFrequency($previousStart, $previousEnd);
|
|
$current = $this->getPurchaseFrequency($start, $end);
|
|
break;
|
|
case StatsShopType::averageBasketHt:
|
|
$previous = $this->getAverageBasketHt($previousStart, $previousEnd);
|
|
$current = $this->getAverageBasketHt($start, $end);
|
|
break;
|
|
case StatsShopType::averageProductCountPerOrder:
|
|
$previous = $this->getAverageProductCountPerOrder($previousStart, $previousEnd);
|
|
$current = $this->getAverageProductCountPerOrder($start, $end);
|
|
break;
|
|
case StatsShopType::caHt:
|
|
$previous = $this->getCaHt($previousStart, $previousEnd);
|
|
$current = $this->getCaHt($start, $end);
|
|
break;
|
|
case StatsShopType::caTtc:
|
|
$previous = $this->getCaTtc($previousStart, $previousEnd);
|
|
$current = $this->getCaTtc($start, $end);
|
|
break;
|
|
case StatsShopType::nbCmdWith7DayDelay:
|
|
$previous = $this->getNbCmdWith7DayDelay($previousStart, $previousEnd);
|
|
$current = $this->getNbCmdWith7DayDelay($start, $end);
|
|
break;
|
|
case StatsShopType::nbCmdWith14DayDelay:
|
|
$previous = $this->getNbCmdWith14DayDelay($previousStart, $previousEnd);
|
|
$current = $this->getNbCmdWith14DayDelay($start, $end);
|
|
break;
|
|
case StatsShopType::nbActiveClients:
|
|
$previous = $this->getNbActiveClients($previousStart, $previousEnd);
|
|
$current = $this->getNbActiveClients($start, $end);
|
|
break;
|
|
case StatsShopType::nbValidateCmd:
|
|
$previous = $this->getNbValidateCmd($previousStart, $previousEnd);
|
|
$current = $this->getNbValidateCmd($start, $end);
|
|
break;
|
|
case StatsShopType::nbWaitingCmd:
|
|
$previous = $this->getNbWaitingCmd($previousStart, $previousEnd);
|
|
$current = $this->getNbWaitingCmd($start, $end);
|
|
break;
|
|
case StatsShopType::nbCanceledCmd:
|
|
$previous = $this->getNbCanceledCmd($previousStart, $previousEnd);
|
|
$current = $this->getNbCanceledCmd($start, $end);
|
|
break;
|
|
case StatsCustomerType::nbSalarie:
|
|
$previous = $this->getActiveEmployeesCount($previousStart, $previousEnd);
|
|
$current = $this->getActiveEmployeesCount($start, $end);
|
|
break;
|
|
case StatsCustomerType::nbSalarieWithAccount:
|
|
$previous = $this->getActiveEmployeesCountWithAnAccount($previousStart, $previousEnd);
|
|
$current = $this->getActiveEmployeesCountWithAnAccount($start, $end);
|
|
break;
|
|
case StatsCustomerType::membershipRate:
|
|
$previous = $this->getMembershipRate($previousStart, $previousEnd);
|
|
$current = $this->getMembershipRate($start, $end);
|
|
break;
|
|
default:
|
|
throw new \InvalidArgumentException("Unknown stats type: {$type->label()}");
|
|
}
|
|
|
|
$stats[$type->value] = [
|
|
'previous' => $previous,
|
|
'current' => $current,
|
|
'diff' => $current - $previous,
|
|
];
|
|
}
|
|
|
|
return $stats;
|
|
}
|
|
|
|
/**
|
|
* Get the percentage of active registered people / people with a generated code
|
|
*/
|
|
public function getMembershipRate(CarbonInterface $start, CarbonInterface $end): float
|
|
{
|
|
$registered = $this->getActiveEmployeesCountWithAnAccount($start, $end);
|
|
$employee = $this->getActiveEmployeesCount($start, $end);
|
|
|
|
return $employee ? round($registered / $employee * 100, 2) : 0.0;
|
|
}
|
|
|
|
/**
|
|
* Get the previous period of the selected date.
|
|
*/
|
|
public function getPreviousPeriod(CarbonInterface $start, CarbonInterface $end): CarbonPeriod
|
|
{
|
|
$diffDays = $start->copy()->diffInDays($end);
|
|
|
|
return CarbonPeriod::create(
|
|
$start->copy()->subDays($diffDays + 1),
|
|
$start->copy()->subDay()
|
|
);
|
|
}
|
|
|
|
/**
|
|
* Get the percentage of registered people / people with a generated code
|
|
*/
|
|
public function getMembershipPercentage(): float
|
|
{
|
|
$employee = $this->employeeDirectory->countActiveEmployees();
|
|
$registered = $this->employeeDirectory->countActiveRegisteredEmployees();
|
|
|
|
return $employee ? round($registered / $employee * 100, 2) : 0.0;
|
|
}
|
|
|
|
/**
|
|
* Get the number of active employees within the date range.
|
|
*/
|
|
private function getActiveEmployeesCount(CarbonInterface $start, CarbonInterface $end): int
|
|
{
|
|
return $this->employeeDirectory->countActiveEmployeesWithin($start, $end);
|
|
}
|
|
|
|
/**
|
|
* Get the number of active registered employees within the date range.
|
|
*/
|
|
private function getActiveEmployeesCountWithAnAccount(CarbonInterface $start, CarbonInterface $end): int
|
|
{
|
|
return $this->employeeDirectory->countActiveRegisteredEmployeesWithin($start, $end);
|
|
}
|
|
|
|
/**
|
|
* Get all validated orders.
|
|
*
|
|
* @return Collection<int,\App\Models\Order>
|
|
*/
|
|
private function getValidatedOrders(CarbonInterface $start, CarbonInterface $end): Collection
|
|
{
|
|
return $this->orderDirectory->getValidatedOrders($start, $end);
|
|
}
|
|
|
|
/**
|
|
* Get the number of validated command.
|
|
*/
|
|
private function getNbValidateCmd(CarbonInterface $start, CarbonInterface $end): int
|
|
{
|
|
return $this->getValidatedOrders($start, $end)->count();
|
|
}
|
|
|
|
/**
|
|
* Get the number of waiting command.
|
|
*/
|
|
private function getNbWaitingCmd(CarbonInterface $start, CarbonInterface $end): int
|
|
{
|
|
return $this->getOrdersByStatus(OrderStatus::WAITING, $start, $end)->count();
|
|
}
|
|
|
|
/**
|
|
* Get the number of canceled command.
|
|
*/
|
|
private function getNbCanceledCmd(CarbonInterface $start, CarbonInterface $end): int
|
|
{
|
|
return $this->getOrdersByStatus(OrderStatus::CANCELED, $start, $end)->count();
|
|
}
|
|
|
|
/**
|
|
* Get orders by status.
|
|
*
|
|
* @return Collection<int,\App\Models\Order>
|
|
*/
|
|
private function getOrdersByStatus(OrderStatus $statusId, CarbonInterface $start, CarbonInterface $end): Collection
|
|
{
|
|
return $this->orderDirectory->getOrdersByStatus($statusId, $start, $end);
|
|
}
|
|
|
|
/**
|
|
* Get the canceled command rate.
|
|
*/
|
|
private function getCanceledRate(CarbonInterface $start, CarbonInterface $end): float
|
|
{
|
|
$nbWaitingCmd = $this->getNbWaitingCmd($start, $end);
|
|
$nbCanceledCmd = $this->getNbCanceledCmd($start, $end);
|
|
$nbValidateCmd = $this->getNbValidateCmd($start, $end);
|
|
|
|
// Prevent division by 0.
|
|
if (($nbValidateCmd + $nbWaitingCmd + $nbCanceledCmd) !== 0) {
|
|
return round(
|
|
(($nbWaitingCmd + $nbCanceledCmd) / ($nbValidateCmd + $nbWaitingCmd + $nbCanceledCmd)) * 100,
|
|
2
|
|
);
|
|
}
|
|
|
|
return 0.0;
|
|
}
|
|
|
|
/**
|
|
* Get the order frequency.
|
|
*/
|
|
private function getOrderFrequency(CarbonInterface $start, CarbonInterface $end): float
|
|
{
|
|
$nbValidateCmd = $this->getNbValidateCmd($start, $end);
|
|
$period = new CarbonPeriod($start, $end)->count();
|
|
|
|
return round($nbValidateCmd / $period, 2);
|
|
}
|
|
|
|
/**
|
|
* Get the order frequency.
|
|
*/
|
|
private function getPurchaseFrequency(CarbonInterface $start, CarbonInterface $end): float
|
|
{
|
|
$activeClients = $this->getNbActiveClients($start, $end);
|
|
if (! $activeClients) {
|
|
return 0.0;
|
|
}
|
|
$nbValidateCmd = $this->getNbValidateCmd($start, $end);
|
|
|
|
return round($nbValidateCmd / $activeClients, 2);
|
|
}
|
|
|
|
/**
|
|
* Get the number of active clients (ordered in the period).
|
|
*/
|
|
private function getNbActiveClients(CarbonInterface $start, CarbonInterface $end): int
|
|
{
|
|
return $this->orderDirectory->getNbActiveClients($start, $end);
|
|
}
|
|
|
|
/**
|
|
* Get the number command where the collect day is 7 days after the order.
|
|
*/
|
|
private function getNbCmdWith7DayDelay(CarbonInterface $start, CarbonInterface $end): int
|
|
{
|
|
return $this->orderDirectory->getNbCmdWith7DayDelay($start, $end);
|
|
}
|
|
|
|
/**
|
|
* Get the number command where the collect day is 14 days after the order.
|
|
*/
|
|
private function getNbCmdWith14DayDelay(CarbonInterface $start, CarbonInterface $end): int
|
|
{
|
|
return $this->orderDirectory->getNbCmdWith14DayDelay($start, $end);
|
|
}
|
|
|
|
/**
|
|
* Get the CA HT.
|
|
*/
|
|
private function getCaHt(CarbonInterface $start, CarbonInterface $end): float
|
|
{
|
|
return $this->orderDirectory->getCaHt($start, $end);
|
|
}
|
|
|
|
/**
|
|
* Get the CA TTC.
|
|
*/
|
|
private function getCaTtc(CarbonInterface $start, CarbonInterface $end): float
|
|
{
|
|
return $this->orderDirectory->getCaTtc($start, $end);
|
|
}
|
|
|
|
/**
|
|
* Get the average basket HT.
|
|
*/
|
|
private function getAverageBasketHt(CarbonInterface $start, CarbonInterface $end): float
|
|
{
|
|
// Prevent division by 0.
|
|
if ($this->getNbValidateCmd($start, $end) !== 0) {
|
|
return round($this->getCaHt($start, $end) / $this->getNbValidateCmd($start, $end), 2);
|
|
}
|
|
|
|
return 0.0;
|
|
}
|
|
|
|
/**
|
|
* Get the average product count per order.
|
|
*/
|
|
private function getAverageProductCountPerOrder(CarbonInterface $start, CarbonInterface $end): float
|
|
{
|
|
$nbValidateCmd = $this->getNbValidateCmd($start, $end);
|
|
|
|
// Prevent division by 0.
|
|
if ($nbValidateCmd !== 0) {
|
|
$totalQty = $this->orderDirectory->getTotalQuantity($start, $end);
|
|
|
|
return round((float) $totalQty / $nbValidateCmd, 2);
|
|
}
|
|
|
|
return 0.0;
|
|
}
|
|
}
|