316 lines
12 KiB
PHP
316 lines
12 KiB
PHP
<?php
|
|
|
|
namespace Modules\ManagementTools\Http\Controllers;
|
|
|
|
use Carbon\Carbon;
|
|
use Illuminate\Http\Request;
|
|
use Illuminate\Routing\Controller;
|
|
use Illuminate\Support\Facades\Response;
|
|
use Modules\ManagementTools\Entities\MtExecutiveNote;
|
|
use Modules\ManagementTools\Entities\MtExecutiveTarget;
|
|
use Modules\ManagementTools\Services\ExecutiveCockpitService;
|
|
use Modules\ManagementTools\Utils\ManagementToolsUtil;
|
|
|
|
class ExecutiveCockpitController extends Controller
|
|
{
|
|
public function __construct(
|
|
protected ExecutiveCockpitService $cockpitService,
|
|
protected ManagementToolsUtil $mtUtil
|
|
) {
|
|
}
|
|
|
|
public function index(Request $request)
|
|
{
|
|
$this->authorizeCockpitView();
|
|
|
|
$context = $this->resolveCockpitContext($request);
|
|
$viewData = $this->buildCockpitViewData($context, true);
|
|
|
|
if (function_exists('activity')) {
|
|
activity('managementtools')
|
|
->withProperties([
|
|
'business_id' => $context['businessId'],
|
|
'start_date' => $context['startDate']->toDateString(),
|
|
'end_date' => $context['endDate']->toDateString(),
|
|
'active_tab' => $context['activeTab'],
|
|
])
|
|
->log('executive_cockpit_viewed');
|
|
}
|
|
|
|
return view('managementtools::executive_cockpit.index', $viewData);
|
|
}
|
|
|
|
public function content(Request $request)
|
|
{
|
|
$this->authorizeCockpitView();
|
|
|
|
$context = $this->resolveCockpitContext($request);
|
|
|
|
return view('managementtools::executive_cockpit.partials.content', $this->buildCockpitViewData($context, true));
|
|
}
|
|
|
|
public function drillTab(Request $request)
|
|
{
|
|
$this->authorizeCockpitView();
|
|
|
|
$context = $this->resolveCockpitContext($request);
|
|
$tabPayload = $this->cockpitService->buildDrilldownTabForViewer(
|
|
$context['businessId'],
|
|
$context['startDate'],
|
|
$context['endDate'],
|
|
$context['activeTab'],
|
|
auth()->user()
|
|
);
|
|
|
|
if (! $tabPayload) {
|
|
abort(404);
|
|
}
|
|
|
|
return view('managementtools::executive_cockpit.partials.drill_tab_body', [
|
|
'data' => [
|
|
'trend_month_labels' => $tabPayload['trend_month_labels'],
|
|
'drilldown_labels' => $tabPayload['drilldown_labels'],
|
|
],
|
|
'tab_key' => $tabPayload['tab_key'],
|
|
'section' => $tabPayload['section'],
|
|
]);
|
|
}
|
|
|
|
public function saveTargets(Request $request)
|
|
{
|
|
$this->authorizeCockpitManage();
|
|
$businessId = (int) $request->session()->get('user.business_id');
|
|
|
|
$request->validate([
|
|
'targets.sales_this_month' => 'nullable|numeric',
|
|
'targets.gross_margin_estimate' => 'nullable|numeric',
|
|
'targets.workforce_productivity' => 'nullable|numeric',
|
|
]);
|
|
|
|
$metrics = $request->input('targets', []);
|
|
foreach (['sales_this_month', 'gross_margin_estimate', 'workforce_productivity'] as $metric) {
|
|
if (! isset($metrics[$metric]) || $metrics[$metric] === '') {
|
|
continue;
|
|
}
|
|
|
|
MtExecutiveTarget::create([
|
|
'business_id' => $businessId,
|
|
'metric_key' => $metric,
|
|
'target_value' => (float) $metrics[$metric],
|
|
'effective_from' => Carbon::today()->toDateString(),
|
|
'created_by' => auth()->id(),
|
|
]);
|
|
|
|
if (function_exists('activity')) {
|
|
activity('managementtools')
|
|
->withProperties([
|
|
'business_id' => $businessId,
|
|
'metric' => $metric,
|
|
'target_value' => (float) $metrics[$metric],
|
|
])
|
|
->log('executive_target_saved');
|
|
}
|
|
}
|
|
|
|
return redirect()->back()->with('status', ['success' => true, 'msg' => __('managementtools::lang.targets_saved')]);
|
|
}
|
|
|
|
public function exportPdf(Request $request)
|
|
{
|
|
$this->authorizeCockpitView();
|
|
$businessId = (int) $request->session()->get('user.business_id');
|
|
$start = Carbon::parse($this->mtUtil->parseInputDate($request->input('start_date')) ?: Carbon::today()->subDays(29)->toDateString())->startOfDay();
|
|
$end = Carbon::parse($this->mtUtil->parseInputDate($request->input('end_date')) ?: Carbon::today()->toDateString())->endOfDay();
|
|
$data = $this->cockpitService->build($businessId, $start, $end);
|
|
|
|
$html = view('managementtools::executive_cockpit.pdf', compact('data'))->render();
|
|
$mpdf = new \Mpdf\Mpdf(['tempDir' => storage_path('app/mpdf-temp')]);
|
|
$mpdf->WriteHTML($html);
|
|
|
|
return Response::make($mpdf->Output('executive-cockpit.pdf', 'S'), 200, [
|
|
'Content-Type' => 'application/pdf',
|
|
'Content-Disposition' => 'inline; filename="executive-cockpit.pdf"',
|
|
]);
|
|
}
|
|
|
|
public function exportBoardPackPdf(Request $request)
|
|
{
|
|
$this->authorizeCockpitView();
|
|
$businessId = (int) $request->session()->get('user.business_id');
|
|
$start = Carbon::parse($this->mtUtil->parseInputDate($request->input('start_date')) ?: Carbon::today()->subDays(29)->toDateString())->startOfDay();
|
|
$end = Carbon::parse($this->mtUtil->parseInputDate($request->input('end_date')) ?: Carbon::today()->toDateString())->endOfDay();
|
|
$data = $this->cockpitService->build($businessId, $start, $end);
|
|
|
|
if (class_exists(\Modules\IntegrationHub\Events\ExecutiveCockpitExported::class)) {
|
|
event(new \Modules\IntegrationHub\Events\ExecutiveCockpitExported($businessId, $data));
|
|
}
|
|
|
|
$html = view('managementtools::executive_cockpit.board_pack_pdf', compact('data'))->render();
|
|
$mpdf = new \Mpdf\Mpdf(['tempDir' => storage_path('app/mpdf-temp')]);
|
|
$mpdf->WriteHTML($html);
|
|
|
|
return Response::make($mpdf->Output('board-pack.pdf', 'S'), 200, [
|
|
'Content-Type' => 'application/pdf',
|
|
'Content-Disposition' => 'inline; filename="board-pack.pdf"',
|
|
]);
|
|
}
|
|
|
|
public function saveNote(Request $request)
|
|
{
|
|
$this->authorizeCockpitManage();
|
|
$businessId = (int) $request->session()->get('user.business_id');
|
|
|
|
$request->validate([
|
|
'title' => 'required|string|max:255',
|
|
'note' => 'required|string|max:5000',
|
|
]);
|
|
|
|
MtExecutiveNote::create([
|
|
'business_id' => $businessId,
|
|
'user_id' => auth()->id(),
|
|
'title' => $request->input('title'),
|
|
'note' => $request->input('note'),
|
|
'note_date' => Carbon::today()->toDateString(),
|
|
'visibility' => 'leadership',
|
|
]);
|
|
|
|
if (function_exists('activity')) {
|
|
activity('managementtools')
|
|
->withProperties([
|
|
'business_id' => $businessId,
|
|
'title' => $request->input('title'),
|
|
])
|
|
->log('executive_note_saved');
|
|
}
|
|
|
|
return redirect()->back()->with('status', ['success' => true, 'msg' => __('managementtools::lang.note_saved')]);
|
|
}
|
|
|
|
protected function resolveCockpitContext(Request $request): array
|
|
{
|
|
$businessId = (int) $request->session()->get('user.business_id');
|
|
$start = $this->mtUtil->parseInputDate($request->input('start_date')) ?: Carbon::today()->subDays(29)->toDateString();
|
|
$end = $this->mtUtil->parseInputDate($request->input('end_date')) ?: Carbon::today()->toDateString();
|
|
$validTabs = ['finance', 'sales', 'maintenance', 'projects', 'workforce', 'crm', 'accounting', 'manufacturing', 'ie'];
|
|
$activeTab = in_array($request->input('tab'), $validTabs, true) ? $request->input('tab') : 'finance';
|
|
|
|
return [
|
|
'businessId' => $businessId,
|
|
'startDate' => Carbon::parse($start)->startOfDay(),
|
|
'endDate' => Carbon::parse($end)->endOfDay(),
|
|
'activeTab' => $activeTab,
|
|
];
|
|
}
|
|
|
|
protected function buildCockpitViewData(array $context, bool $lazyDrillTabs = false): array
|
|
{
|
|
$data = $this->cockpitService->buildForViewer(
|
|
$context['businessId'],
|
|
$context['startDate'],
|
|
$context['endDate'],
|
|
auth()->user(),
|
|
$lazyDrillTabs,
|
|
$context['activeTab']
|
|
);
|
|
|
|
$startDate = $this->mtUtil->formatForInput($context['startDate']->toDateString());
|
|
$endDate = $this->mtUtil->formatForInput($context['endDate']->toDateString());
|
|
|
|
return [
|
|
'data' => $data,
|
|
'start_date' => $startDate,
|
|
'end_date' => $endDate,
|
|
'active_tab' => $context['activeTab'],
|
|
'quick_links' => $this->quickLinks(),
|
|
'date_presets' => $this->datePresets(),
|
|
'export_urls' => $this->exportUrls($startDate, $endDate),
|
|
'content_url' => action([self::class, 'content']),
|
|
'drill_tab_url' => action([self::class, 'drillTab']),
|
|
'lazy_drill_tabs' => true,
|
|
];
|
|
}
|
|
|
|
protected function quickLinks(): array
|
|
{
|
|
return [
|
|
['title' => __('managementtools::lang.open_sales_report'), 'url' => url('/reports/product-sell-report')],
|
|
['title' => __('managementtools::lang.open_payment_report'), 'url' => url('/reports/sell-payment-report')],
|
|
['title' => __('managementtools::lang.open_maintenance_board'), 'url' => url('/maintenance/dashboard')],
|
|
['title' => __('managementtools::lang.open_ticket_center'), 'url' => url('/management-tools/tickets')],
|
|
['title' => __('managementtools::lang.open_project_center'), 'url' => url('/management-tools/project-categories')],
|
|
['title' => __('managementtools::lang.open_crm_board'), 'url' => url('/crm/dashboard')],
|
|
['title' => __('managementtools::lang.open_accounting_dashboard'), 'url' => url('/accounting/dashboard')],
|
|
['title' => __('managementtools::lang.open_manufacturing_board'), 'url' => url('/manufacturing/production')],
|
|
['title' => __('managementtools::lang.open_ie_dashboard'), 'url' => url('/industrial-engineering/dashboard')],
|
|
];
|
|
}
|
|
|
|
protected function datePresets(): array
|
|
{
|
|
$today = Carbon::today();
|
|
|
|
return [
|
|
[
|
|
'key' => '7d',
|
|
'label' => __('managementtools::lang.range_7_days'),
|
|
'start' => $this->mtUtil->formatForInput($today->copy()->subDays(6)->toDateString()),
|
|
'end' => $this->mtUtil->formatForInput($today->toDateString()),
|
|
],
|
|
[
|
|
'key' => '30d',
|
|
'label' => __('managementtools::lang.range_30_days'),
|
|
'start' => $this->mtUtil->formatForInput($today->copy()->subDays(29)->toDateString()),
|
|
'end' => $this->mtUtil->formatForInput($today->toDateString()),
|
|
],
|
|
[
|
|
'key' => 'month',
|
|
'label' => __('managementtools::lang.range_this_month'),
|
|
'start' => $this->mtUtil->formatForInput($today->copy()->startOfMonth()->toDateString()),
|
|
'end' => $this->mtUtil->formatForInput($today->toDateString()),
|
|
],
|
|
];
|
|
}
|
|
|
|
protected function exportUrls(string $startDate, string $endDate): array
|
|
{
|
|
$urls = [
|
|
'board_pack' => action([self::class, 'exportBoardPackPdf'], [
|
|
'start_date' => $startDate,
|
|
'end_date' => $endDate,
|
|
]),
|
|
'pdf' => action([self::class, 'exportPdf'], [
|
|
'start_date' => $startDate,
|
|
'end_date' => $endDate,
|
|
]),
|
|
];
|
|
|
|
if (\Module::has('IntegrationHub') && \Module::isEnabled('IntegrationHub') && auth()->user()->can('integrationhub.export')) {
|
|
$urls['bi_exports'] = url('/integrationhub/exports');
|
|
}
|
|
|
|
return $urls;
|
|
}
|
|
|
|
protected function authorizeCockpitView(): void
|
|
{
|
|
if (
|
|
! auth()->user()->can('managementtools.access')
|
|
|| ! auth()->user()->can('managementtools.daily_report_all')
|
|
|| ! auth()->user()->can('managementtools.board_view')
|
|
) {
|
|
abort(403, 'Unauthorized action.');
|
|
}
|
|
}
|
|
|
|
protected function authorizeCockpitManage(): void
|
|
{
|
|
if (
|
|
! auth()->user()->can('managementtools.access')
|
|
|| ! auth()->user()->can('managementtools.daily_report_all')
|
|
|| ! auth()->user()->can('managementtools.board_manage')
|
|
) {
|
|
abort(403, 'Unauthorized action.');
|
|
}
|
|
}
|
|
}
|