commonUtil = $commonUtil; $this->moduleUtil = $moduleUtil; } public function getBusinessId(): int { return (int) request()->session()->get('user.business_id'); } public function getBusiness(): ?Business { $business_id = $this->getBusinessId(); return $business_id ? Business::find($business_id) : null; } public function getCategoriesDropdown($business_id, $exclude_id = null): array { $categories = EquipmentCategory::where('business_id', $business_id) ->where('is_active', true) ->orderBy('name') ->get(['id', 'name', 'parent_id']); $dropdown = []; $this->buildCategoryDropdown($categories, null, $dropdown, 0, $exclude_id); return $dropdown; } protected function buildCategoryDropdown($categories, $parent_id, &$dropdown, $depth, $exclude_id): void { foreach ($categories->where('parent_id', $parent_id) as $category) { if ($exclude_id && (int) $category->id === (int) $exclude_id) { continue; } $prefix = str_repeat('— ', $depth); $dropdown[$category->id] = $prefix.$category->name; $this->buildCategoryDropdown($categories, $category->id, $dropdown, $depth + 1, $exclude_id); } } public function getProductionLinesDropdown($business_id, $project_id = null): array { $query = ProductionLine::where('business_id', $business_id) ->where('status', 'active') ->orderBy('name'); if ($project_id) { $query->where('project_id', $project_id); } return $query->get()->mapWithKeys(function ($line) { $label = $line->code ? "{$line->code} — {$line->name}" : $line->name; return [$line->id => $label]; })->toArray(); } public function getProjectsDropdown($business_id): array { if (! class_exists(\Modules\Project\Entities\Project::class)) { return []; } if (! $this->moduleUtil->isModuleInstalled('Project')) { return []; } return \Modules\Project\Entities\Project::where('business_id', $business_id) ->orderBy('name') ->pluck('name', 'id') ->toArray(); } public function getCustomersDropdown($business_id): array { return Contact::customersDropdown($business_id, false)->toArray(); } public function getEquipmentDropdown($business_id, $project_id = null, $production_line_id = null): array { $query = Equipment::where('business_id', $business_id) ->orderBy('name'); if ($production_line_id) { $query->where('production_line_id', $production_line_id); } elseif ($project_id) { $query->where('project_id', $project_id); } return $query->get()->mapWithKeys(function ($eq) { $label = $eq->code ? "{$eq->code} — {$eq->name}" : $eq->name; return [$eq->id => $label]; })->toArray(); } public function getUsersDropdown($business_id): array { return User::forDropdown($business_id, true); } public function statusLabels(): array { return [ 'active' => 'فعال', 'inactive' => 'غیرفعال', 'under_maintenance' => 'در حال تعمیر', 'under_overhaul' => 'در حال اورهال', 'under_rebuild' => 'در حال بازسازی', 'retired' => 'مستهلک', 'draft' => 'پیش‌نویس', 'open' => 'باز', 'in_progress' => 'در حال انجام', 'on_hold' => 'معلق', 'completed' => 'تکمیل‌شده', 'cancelled' => 'لغو‌شده', 'planned' => 'برنامه‌ریزی‌شده', 'approved' => 'تأیید‌شده', 'waiting' => 'در انتظار', 'suspended' => 'متوقف', 'scheduled' => 'زمان‌بندی‌شده', 'pending' => 'در انتظار بررسی', 'passed' => 'قبول', 'failed' => 'رد', ]; } public function priorityLabels(): array { return [ 'low' => 'کم', 'medium' => 'متوسط', 'high' => 'بالا', 'critical' => 'بحرانی', 'urgent' => 'فوری', ]; } public function formatMoney($amount): string { return $this->commonUtil->num_f($amount, true); } public function parseInputDate(?string $date): ?string { if (empty($date)) { return null; } if (function_exists('jalali_to_gregorian')) { $converted = jalali_to_gregorian($date, session('business.date_format', 'Y/m/d'), false); if (! empty($converted) && preg_match('/^\d{4}-\d{2}-\d{2}/', $converted)) { return $converted; } } return $this->commonUtil->uf_date($date); } public function parseInputDateTime(?string $date): ?string { if (empty($date)) { return null; } if (function_exists('jalali_to_gregorian')) { $converted = jalali_to_gregorian($date, session('business.date_format', 'Y/m/d'), true); if (! empty($converted) && preg_match('/^\d{4}-\d{2}-\d{2}/', $converted)) { return $converted; } } return $this->commonUtil->uf_date($date, true); } public function formatDate($date): ?string { if (empty($date)) { return null; } try { $carbon = $date instanceof \Carbon\Carbon ? $date->copy() : \Carbon\Carbon::parse($date); $format = session('business.date_format', 'Y/m/d'); $formatted = format_jalali_date($carbon, $format); return function_exists('persian_number') ? persian_number($formatted) : $formatted; } catch (\Exception $e) { return format_date($date); } } public function formatDateTime($date): ?string { if (empty($date)) { return null; } try { $carbon = $date instanceof \Carbon\Carbon ? $date->copy() : \Carbon\Carbon::parse($date); $format = session('business.date_format', 'Y/m/d'); $time_format = session('business.time_format', 24) == 12 ? ' h:i A' : ' H:i'; $formatted = format_jalali_date($carbon, $format.$time_format); return function_exists('persian_number') ? persian_number($formatted) : $formatted; } catch (\Exception $e) { return format_datetime($date); } } public function formatMonthLabel(\Carbon\Carbon $date): string { try { $formatted = format_jalali_date($date, 'Y/m'); return function_exists('persian_number') ? persian_number($formatted) : $formatted; } catch (\Exception $e) { return $date->format('Y-m'); } } protected function apiDateFields(): array { return [ 'installation_date' => false, 'warranty_expires_at' => false, 'last_service_date' => false, 'next_service_date' => false, 'last_overhaul_date' => false, 'next_overhaul_date' => false, 'start_date' => false, 'end_date' => false, 'replaced_at' => false, 'expected_replacement_date' => false, 'last_replaced_at' => false, 'effective_date' => false, 'scheduled_at' => true, 'completed_at' => true, 'started_at' => true, 'reported_at' => true, 'visit_date' => true, 'performed_at' => true, 'next_due_at' => true, 'last_performed_at' => true, 'created_at' => true, 'updated_at' => true, 'read_at' => true, 'sent_at' => true, 'approved_at' => true, ]; } public function appendJalaliDatesToApiPayload(mixed $data): mixed { if ($data instanceof \Illuminate\Database\Eloquent\Model) { $data = $data->toArray(); } elseif ($data instanceof \Illuminate\Support\Collection) { $data = $data->toArray(); } if (! is_array($data)) { return $data; } if (array_is_list($data)) { return array_map(fn ($item) => $this->appendJalaliDatesToApiPayload($item), $data); } foreach ($this->apiDateFields() as $field => $isDatetime) { if (! array_key_exists($field, $data) || $data[$field] === null || $data[$field] === '') { continue; } $data[$field.'_jalali'] = $isDatetime ? $this->formatDateTime($data[$field]) : $this->formatDate($data[$field]); } foreach ($data as $key => $value) { if (is_array($value)) { $data[$key] = $this->appendJalaliDatesToApiPayload($value); } } return $data; } public function statusLabel(?string $status): string { return $this->statusLabels()[$status] ?? ($status ?: '—'); } public function priorityLabel(?string $priority): string { return $this->priorityLabels()[$priority] ?? ($priority ?: '—'); } public function jsonOrRedirect(\Illuminate\Http\Request $request, bool $success, string $msg, ?string $redirect = null) { $output = ['success' => $success, 'msg' => $msg]; if ($request->ajax() || $request->wantsJson()) { return response()->json($output); } if ($success) { return redirect()->to($redirect ?? url()->previous())->with('status', $msg); } return redirect()->back()->with('status', $msg); } public function getAssetsDropdown($business_id, $project_id = null): array { if (! class_exists(\Modules\AssetManagement\Entities\Asset::class) || ! $this->moduleUtil->isModuleInstalled('AssetManagement')) { return []; } $query = \Modules\AssetManagement\Entities\Asset::where('business_id', $business_id) ->orderBy('name'); if ($project_id) { $query->where(function ($q) use ($project_id) { $q->where('project_id', $project_id)->orWhereNull('project_id'); }); } return $query->get(['id', 'asset_code', 'name']) ->mapWithKeys(function ($asset) { $label = $asset->asset_code ? "{$asset->asset_code} — {$asset->name}" : $asset->name; return [$asset->id => $label]; }) ->toArray(); } public function getPartCatalogsDropdown($business_id): array { if (! class_exists(\Modules\Maintenance\Models\PartCatalog::class)) { return []; } return \Modules\Maintenance\Models\PartCatalog::where('business_id', $business_id) ->where('status', 'active') ->orderBy('name') ->get() ->mapWithKeys(fn ($c) => [$c->id => ($c->catalog_code ? $c->catalog_code.' — ' : '').$c->name]) ->toArray(); } public function getSparePartsDropdown($business_id): array { return \Modules\Maintenance\Models\SparePart::where('business_id', $business_id) ->orderBy('name') ->get() ->mapWithKeys(fn ($p) => [$p->id => ($p->part_number ? $p->part_number.' — ' : '').$p->name]) ->toArray(); } public function getServiceProvidersDropdown($business_id): array { if (! class_exists(\Modules\Maintenance\Models\ServiceProvider::class)) { return []; } return \Modules\Maintenance\Models\ServiceProvider::where('business_id', $business_id) ->orderBy('name') ->pluck('name', 'id') ->toArray(); } public function getExternalServiceProvidersDropdown($business_id): array { if (! class_exists(\Modules\Maintenance\Models\ServiceProvider::class)) { return []; } return \Modules\Maintenance\Models\ServiceProvider::where('business_id', $business_id) ->where('provider_type', 'external') ->where('is_active', true) ->orderBy('name') ->pluck('name', 'id') ->toArray(); } public function getHoldingEntitiesDropdown($business_id): array { if (! class_exists(\App\HoldingEntity::class)) { return []; } return \App\HoldingEntity::where('business_id', $business_id) ->where('is_active', true) ->orderBy('name') ->pluck('name', 'id') ->toArray(); } public function getOrgUnitsDropdown($business_id, $entity_id = null): array { if (! class_exists(\App\OrgUnit::class)) { return []; } $query = \App\OrgUnit::query() ->whereHas('entity', fn ($q) => $q->where('business_id', $business_id)) ->where('is_active', true) ->orderBy('name'); if ($entity_id) { $query->where('entity_id', $entity_id); } return $query->pluck('name', 'id')->toArray(); } public function getEquipmentPartsDropdown($equipment_id, $exclude_id = null): array { $parts = \Modules\Maintenance\Models\EquipmentPart::where('equipment_id', $equipment_id) ->orderBy('part_name') ->get(['id', 'part_name', 'parent_id']); $dropdown = []; $this->buildPartDropdown($parts, null, $dropdown, 0, $exclude_id); return $dropdown; } protected function buildPartDropdown($parts, $parent_id, &$dropdown, $depth, $exclude_id): void { foreach ($parts->where('parent_id', $parent_id) as $part) { if ($exclude_id && (int) $part->id === (int) $exclude_id) { continue; } $prefix = str_repeat('— ', $depth); $dropdown[$part->id] = $prefix.$part->part_name; $this->buildPartDropdown($parts, $part->id, $dropdown, $depth + 1, $exclude_id); } } public function partTypeLabels(): array { return [ 'mechanical' => __('maintenance::lang.part_type_mechanical'), 'electronic' => __('maintenance::lang.part_type_electronic'), 'consumable' => __('maintenance::lang.part_type_consumable'), 'hydraulic' => __('maintenance::lang.part_type_hydraulic'), 'pneumatic' => __('maintenance::lang.part_type_pneumatic'), ]; } public function warrantyStatusLabels(): array { return [ 'none' => __('maintenance::lang.warranty_none'), 'active' => __('maintenance::lang.warranty_active'), 'expired' => __('maintenance::lang.warranty_expired'), ]; } public function getMaintenanceSettings($business_id): array { if (! \Illuminate\Support\Facades\Schema::hasColumn('business', 'maintenance_settings')) { return []; } $raw = Business::where('id', $business_id)->value('maintenance_settings'); return ! empty($raw) ? (json_decode($raw, true) ?: []) : []; } public function pmRemindersEnabled($business_id): bool { $settings = $this->getMaintenanceSettings($business_id); return ! array_key_exists('auto_pm_reminders', $settings) || ! empty($settings['auto_pm_reminders']); } public function pmAutoWorkOrderEnabled($business_id): bool { $settings = $this->getMaintenanceSettings($business_id); return ! empty($settings['auto_create_pm_work_order']); } public function isAccountingEnabled($business_id): bool { if (! class_exists(\Modules\Accounting\Entities\AccountingAccount::class)) { return false; } return $this->moduleUtil->isModuleInstalled('Accounting') && $this->moduleUtil->hasThePermissionInSubscription($business_id, 'accounting_module'); } public function isAssetManagementEnabled($business_id): bool { return class_exists(\Modules\AssetManagement\Entities\Asset::class) && $this->moduleUtil->isModuleInstalled('AssetManagement') && $this->moduleUtil->hasThePermissionInSubscription($business_id, 'assetmanagement_module'); } public function isCrmEnabled($business_id): bool { return class_exists(\Modules\Crm\Entities\Schedule::class) && $this->moduleUtil->isModuleInstalled('Crm') && $this->moduleUtil->hasThePermissionInSubscription($business_id, 'crm_module'); } public function getAssetCategoriesDropdown($business_id): array { if (! class_exists(\App\Category::class)) { return []; } return \App\Category::forDropdown($business_id, 'asset')->toArray(); } public function getAccountingAccountsDropdown($business_id): array { if (! $this->isAccountingEnabled($business_id)) { return []; } return \Modules\Accounting\Entities\AccountingAccount::forDropdown($business_id)->toArray(); } public function buildEquipmentPartsTree($parts, ?int $parentId = null): array { $branch = []; foreach ($parts as $part) { if ((int) $part->parent_id === (int) $parentId) { $branch[] = [ 'part' => $part, 'children' => $this->buildEquipmentPartsTree($parts, $part->id), ]; } } return $branch; } public function getLocationsDropdown($business_id): array { if (! class_exists(\App\BusinessLocation::class)) { return []; } $locations = \App\BusinessLocation::forDropdown($business_id, false, false, true, false); return $locations instanceof \Illuminate\Support\Collection ? $locations->toArray() : (array) $locations; } public function getProductsDropdown($business_id, int $limit = 500): array { return \App\Product::where('business_id', $business_id) ->where('type', '!=', 'modifier') ->orderBy('name') ->limit($limit) ->pluck('name', 'id') ->toArray(); } public function toolStatusLabels(): array { return [ 'available' => __('maintenance::lang.tool_status_available'), 'checked_out' => __('maintenance::lang.tool_status_checked_out'), 'maintenance' => __('maintenance::lang.tool_status_maintenance'), 'retired' => __('maintenance::lang.tool_status_retired'), ]; } public function toolStatusLabel(?string $status): string { return $this->toolStatusLabels()[$status] ?? ($status ?: '—'); } }