Files
MokoSuiteClient/source/packages/com_mokosuiteclient/admin/src/Model/ErpReportsModel.php
T
Jonathan Miller 4b9a675d0f
Generic: Repo Health / Site Health (push) Has been skipped
Generic: Repo Health / Access control (push) Successful in 1s
Generic: Project CI / Lint & Validate (push) Successful in 36s
Platform: moko-platform CI / Gate 1: Code Quality (push) Failing after 40s
Generic: Project CI / Tests (push) Has been cancelled
Platform: moko-platform CI / Gate 2: Unit Tests (8.1) (push) Has been cancelled
Platform: moko-platform CI / Gate 2: Unit Tests (8.2) (push) Has been cancelled
Platform: moko-platform CI / Gate 2: Unit Tests (8.3) (push) Has been cancelled
Platform: moko-platform CI / Gate 3: Self-Health Check (push) Has been cancelled
Platform: moko-platform CI / Gate 4: Governance (push) Has been cancelled
Platform: moko-platform CI / Gate 5: Template Integrity (push) Has been cancelled
Platform: moko-platform CI / CI Summary (push) Has been cancelled
Generic: Repo Health / Scripts governance (push) Has been cancelled
Generic: Repo Health / Repository health (push) Has been cancelled
Generic: Repo Health / Report Issues (push) Has been cancelled
Rename MokoSuite → MokoSuiteClient (full element rename)
All Joomla element names, PHP classes, language files, folder structure,
and manifest references renamed from mokosuite to mokosuiteclient.
This repo is now the client-facing tracker for the MokoSuite platform.
2026-06-15 05:19:13 -05:00

81 lines
3.9 KiB
PHP

<?php
namespace Moko\Component\MokoSuiteClient\Administrator\Model;
defined('_JEXEC') or die;
use Joomla\CMS\MVC\Model\BaseDatabaseModel;
class ErpReportsModel extends BaseDatabaseModel
{
public function getSalesReport(string $from, string $to, string $groupBy = 'month'): array
{
$db = $this->getDatabase();
$fmt = match ($groupBy) { 'day' => '%Y-%m-%d', 'week' => '%Y-W%v', 'year' => '%Y', default => '%Y-%m' };
$db->setQuery($db->getQuery(true)
->select('DATE_FORMAT(inv.created, ' . $db->quote($fmt) . ') AS period')
->select('COUNT(*) AS invoice_count, COALESCE(SUM(inv.total), 0) AS revenue, COALESCE(SUM(inv.amount_paid), 0) AS collected')
->from($db->quoteName('#__mokosuiteclient_erp_invoices', 'inv'))
->where($db->quoteName('inv.created') . ' >= ' . $db->quote($from))
->where($db->quoteName('inv.created') . ' <= ' . $db->quote($to . ' 23:59:59'))
->where($db->quoteName('inv.type') . ' = ' . $db->quote('standard'))
->group('period')->order('period ASC'));
return $db->loadObjectList() ?: [];
}
public function getTopCustomers(string $from, string $to, int $limit = 10): array
{
$db = $this->getDatabase();
$db->setQuery($db->getQuery(true)
->select('cd.name AS contact_name, COALESCE(SUM(inv.total), 0) AS total_revenue, COUNT(*) AS invoice_count')
->from($db->quoteName('#__mokosuiteclient_erp_invoices', 'inv'))
->join('LEFT', $db->quoteName('#__contact_details', 'cd') . ' ON cd.id = inv.contact_id')
->where($db->quoteName('inv.created') . ' >= ' . $db->quote($from))
->where($db->quoteName('inv.created') . ' <= ' . $db->quote($to . ' 23:59:59'))
->group('inv.contact_id')->order('total_revenue DESC'), 0, $limit);
return $db->loadObjectList() ?: [];
}
public function getTopProducts(string $from, string $to, int $limit = 10): array
{
$db = $this->getDatabase();
$db->setQuery($db->getQuery(true)
->select('p.sku, c.title AS product_name, COALESCE(SUM(ii.quantity), 0) AS qty_sold, COALESCE(SUM(ii.line_total), 0) AS revenue')
->from($db->quoteName('#__mokosuiteclient_erp_invoice_items', 'ii'))
->join('INNER', $db->quoteName('#__mokosuiteclient_erp_invoices', 'inv') . ' ON inv.id = ii.invoice_id')
->join('LEFT', $db->quoteName('#__mokosuiteclient_erp_products', 'p') . ' ON p.id = ii.product_id')
->join('LEFT', $db->quoteName('#__content', 'c') . ' ON c.id = p.article_id')
->where($db->quoteName('inv.created') . ' >= ' . $db->quote($from))
->where($db->quoteName('inv.created') . ' <= ' . $db->quote($to . ' 23:59:59'))
->where($db->quoteName('ii.product_id') . ' IS NOT NULL')
->group('ii.product_id')->order('revenue DESC'), 0, $limit);
return $db->loadObjectList() ?: [];
}
public function getPipelineReport(string $from, string $to): array
{
$db = $this->getDatabase();
$db->setQuery($db->getQuery(true)
->select('status, COUNT(*) AS cnt, COALESCE(SUM(value), 0) AS total_value')
->from($db->quoteName('#__mokosuiteclient_erp_deals'))
->where($db->quoteName('created') . ' >= ' . $db->quote($from))
->where($db->quoteName('created') . ' <= ' . $db->quote($to . ' 23:59:59'))
->group('status'));
return $db->loadObjectList('status') ?: [];
}
public function getAgingReceivables(): array
{
$db = $this->getDatabase();
$db->setQuery($db->getQuery(true)
->select('inv.id, inv.ref, inv.total, inv.amount_paid, inv.due_date, (inv.total - inv.amount_paid) AS balance, DATEDIFF(CURDATE(), inv.due_date) AS days_overdue')
->select('cd.name AS contact_name')
->from($db->quoteName('#__mokosuiteclient_erp_invoices', 'inv'))
->join('LEFT', $db->quoteName('#__contact_details', 'cd') . ' ON cd.id = inv.contact_id')
->where($db->quoteName('inv.status') . ' IN (' . $db->quote('sent') . ',' . $db->quote('partial') . ',' . $db->quote('overdue') . ')')
->where('(inv.total - inv.amount_paid) > 0')
->order('days_overdue DESC'));
return $db->loadObjectList() ?: [];
}
}