generated from MokoConsulting/Template-Joomla
feat: build out core helpers — 1 files added
This commit is contained in:
@@ -0,0 +1,109 @@
|
||||
<?php
|
||||
namespace Moko\Plugin\System\MokoSuiteBeauty\Helper;
|
||||
|
||||
defined('_JEXEC') or die;
|
||||
|
||||
use Joomla\CMS\Factory;
|
||||
use Joomla\Database\DatabaseInterface;
|
||||
|
||||
/**
|
||||
* Stylist management — schedules, commissions, performance, chair assignment.
|
||||
*/
|
||||
class StylistHelper
|
||||
{
|
||||
/**
|
||||
* Get all active stylists with current stats.
|
||||
*/
|
||||
public static function getAll(): array
|
||||
{
|
||||
$db = Factory::getContainer()->get(DatabaseInterface::class);
|
||||
|
||||
$db->setQuery($db->getQuery(true)
|
||||
->select('s.id, s.specialties, s.commission_rate, s.chair_id')
|
||||
->select('cd.name AS stylist_name, cd.telephone')
|
||||
->select('ch.name AS chair_name')
|
||||
->select('(SELECT COUNT(*) FROM #__mokosuitebeauty_bookings b WHERE b.stylist_id = s.id AND DATE(b.start_time) = CURDATE() AND b.status != ' . $db->quote('cancelled') . ') AS today_bookings')
|
||||
->from($db->quoteName('#__mokosuitebeauty_stylists', 's'))
|
||||
->join('LEFT', $db->quoteName('#__contact_details', 'cd') . ' ON cd.id = s.contact_id')
|
||||
->join('LEFT', $db->quoteName('#__mokosuitebeauty_chairs', 'ch') . ' ON ch.id = s.chair_id')
|
||||
->where($db->quoteName('s.status') . ' = ' . $db->quote('active'))
|
||||
->order('cd.name ASC'));
|
||||
|
||||
return $db->loadObjectList() ?: [];
|
||||
}
|
||||
|
||||
/**
|
||||
* Get stylist performance for a period.
|
||||
*/
|
||||
public static function getPerformance(int $stylistId, string $from = '', string $to = ''): object
|
||||
{
|
||||
$from = $from ?: date('Y-m-01');
|
||||
$to = $to ?: date('Y-m-d');
|
||||
|
||||
if (!\DateTime::createFromFormat('Y-m-d', $from) || !\DateTime::createFromFormat('Y-m-d', $to)) {
|
||||
throw new \InvalidArgumentException('Date parameters must be Y-m-d format.');
|
||||
}
|
||||
|
||||
$db = Factory::getContainer()->get(DatabaseInterface::class);
|
||||
|
||||
$db->setQuery($db->getQuery(true)
|
||||
->select('COUNT(*) AS total_bookings')
|
||||
->select('SUM(CASE WHEN b.status = ' . $db->quote('completed') . ' THEN 1 ELSE 0 END) AS completed')
|
||||
->select('SUM(CASE WHEN b.status = ' . $db->quote('no_show') . ' THEN 1 ELSE 0 END) AS no_shows')
|
||||
->select('COALESCE(SUM(sv.price), 0) AS total_revenue')
|
||||
->select('COUNT(DISTINCT b.client_contact_id) AS unique_clients')
|
||||
->from($db->quoteName('#__mokosuitebeauty_bookings', 'b'))
|
||||
->join('LEFT', $db->quoteName('#__mokosuitebeauty_services', 'sv') . ' ON sv.id = b.service_id')
|
||||
->where('b.stylist_id = ' . (int) $stylistId)
|
||||
->where('DATE(b.start_time) BETWEEN ' . $db->quote($from) . ' AND ' . $db->quote($to)));
|
||||
|
||||
$stats = $db->loadObject();
|
||||
|
||||
$revenue = (float) ($stats->total_revenue ?? 0);
|
||||
|
||||
// Get commission rate
|
||||
$db->setQuery($db->getQuery(true)->select('commission_rate')->from('#__mokosuitebeauty_stylists')->where('id = ' . (int) $stylistId));
|
||||
$rate = (float) $db->loadResult();
|
||||
|
||||
return (object) [
|
||||
'stylist_id' => $stylistId,
|
||||
'total_bookings' => (int) ($stats->total_bookings ?? 0),
|
||||
'completed' => (int) ($stats->completed ?? 0),
|
||||
'no_shows' => (int) ($stats->no_shows ?? 0),
|
||||
'unique_clients' => (int) ($stats->unique_clients ?? 0),
|
||||
'total_revenue' => round($revenue, 2),
|
||||
'commission_earned'=> round($revenue * ($rate / 100), 2),
|
||||
'avg_ticket' => (int) ($stats->completed ?? 0) > 0 ? round($revenue / (int) $stats->completed, 2) : 0,
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Get leaderboard — stylists ranked by revenue.
|
||||
*/
|
||||
public static function getLeaderboard(string $from = '', string $to = ''): array
|
||||
{
|
||||
$from = $from ?: date('Y-m-01');
|
||||
$to = $to ?: date('Y-m-d');
|
||||
|
||||
if (!\DateTime::createFromFormat('Y-m-d', $from) || !\DateTime::createFromFormat('Y-m-d', $to)) {
|
||||
throw new \InvalidArgumentException('Date parameters must be Y-m-d format.');
|
||||
}
|
||||
|
||||
$db = Factory::getContainer()->get(DatabaseInterface::class);
|
||||
|
||||
$db->setQuery($db->getQuery(true)
|
||||
->select('s.id AS stylist_id, cd.name AS stylist_name')
|
||||
->select('COUNT(b.id) AS bookings')
|
||||
->select('COALESCE(SUM(sv.price), 0) AS revenue')
|
||||
->from($db->quoteName('#__mokosuitebeauty_bookings', 'b'))
|
||||
->join('INNER', $db->quoteName('#__mokosuitebeauty_stylists', 's') . ' ON s.id = b.stylist_id')
|
||||
->join('LEFT', $db->quoteName('#__contact_details', 'cd') . ' ON cd.id = s.contact_id')
|
||||
->join('LEFT', $db->quoteName('#__mokosuitebeauty_services', 'sv') . ' ON sv.id = b.service_id')
|
||||
->where($db->quoteName('b.status') . ' = ' . $db->quote('completed'))
|
||||
->where('DATE(b.start_time) BETWEEN ' . $db->quote($from) . ' AND ' . $db->quote($to))
|
||||
->group('s.id, cd.name')
|
||||
->order('revenue DESC'));
|
||||
|
||||
return $db->loadObjectList() ?: [];
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user