commonUtil = $commonUtil; } 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 getAexSettings($business_id): array { if (! Schema::hasColumn('business', 'aex_settings')) { return []; } $raw = Business::where('id', $business_id)->value('aex_settings'); return ! empty($raw) ? (json_decode($raw, true) ?: []) : []; } public function getContactsDropdown($business_id): array { $customers = Contact::customersDropdown($business_id, false, true); $suppliers = Contact::suppliersDropdown($business_id, false, true); $customers = $customers instanceof \Illuminate\Support\Collection ? $customers->toArray() : (array) $customers; $suppliers = $suppliers instanceof \Illuminate\Support\Collection ? $suppliers->toArray() : (array) $suppliers; return $customers + $suppliers; } public function formatMoney($amount, $businessOrId = null): string { $business = $this->resolveBusinessContext($businessOrId); return $this->commonUtil->num_f($amount, true, $business); } protected function resolveBusinessContext($businessOrId = null): ?Business { if ($businessOrId instanceof Business) { return $businessOrId; } if ($businessOrId) { return Business::find($businessOrId); } $businessId = $this->getBusinessId(); return $businessId ? Business::find($businessId) : null; } 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 jsonOrRedirect(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 generateListingCode($business_id): string { $settings = $this->getAexSettings($business_id); $prefix = $settings['listing_code_prefix'] ?? 'AEX'; $ref_count = $this->commonUtil->setAndGetReferenceCount('aex_listing', $business_id); $ref_digits = str_pad($ref_count, 4, '0', STR_PAD_LEFT); return $prefix.'-'.\Carbon\Carbon::now()->format('Ym').'-'.$ref_digits; } public function generateAppraisalNumber($business_id): string { $settings = $this->getAexSettings($business_id); $prefix = $settings['appraisal_number_prefix'] ?? 'AAPR'; $ref_count = $this->commonUtil->setAndGetReferenceCount('aex_appraisal', $business_id); $ref_digits = str_pad($ref_count, 4, '0', STR_PAD_LEFT); return $prefix.'-'.\Carbon\Carbon::now()->format('Ym').'-'.$ref_digits; } public function generateDealCode($business_id): string { $settings = $this->getAexSettings($business_id); $prefix = $settings['deal_code_prefix'] ?? 'ADL'; $ref_count = $this->commonUtil->setAndGetReferenceCount('aex_deal', $business_id); $ref_digits = str_pad($ref_count, 4, '0', STR_PAD_LEFT); return $prefix.'-'.\Carbon\Carbon::now()->format('Ym').'-'.$ref_digits; } public function generateInquiryCode($business_id): string { $prefix = $this->getAexSettings($business_id)['inquiry_code_prefix'] ?? 'ARFQ'; $ref_count = $this->commonUtil->setAndGetReferenceCount('aex_inquiry', $business_id); $ref_digits = str_pad($ref_count, 4, '0', STR_PAD_LEFT); return $prefix.'-'.\Carbon\Carbon::now()->format('Ym').'-'.$ref_digits; } public function generateResearchCaseCode($business_id): string { $prefix = $this->getAexSettings($business_id)['research_case_prefix'] ?? 'ARES'; $ref_count = $this->commonUtil->setAndGetReferenceCount('aex_research_case', $business_id); $ref_digits = str_pad($ref_count, 4, '0', STR_PAD_LEFT); return $prefix.'-'.\Carbon\Carbon::now()->format('Ym').'-'.$ref_digits; } public function researchCategoryLabels(): array { return [ 'market_research' => 'تحقیق بازار', 'technical' => 'فنی', 'pricing' => 'قیمت‌گذاری', 'sourcing' => 'تأمین', 'feasibility' => 'امکان‌سنجی', 'general' => 'عمومی', ]; } public function researchCategoryLabel(?string $cat): string { return $this->researchCategoryLabels()[$cat] ?? ($cat ?: '—'); } public function statusLabels(): array { return [ 'draft' => 'پیش‌نویس', 'submitted' => 'ارسال‌شده', 'under_review' => 'در حال بررسی', 'appraised' => 'کارشناسی‌شده', 'in_deal' => 'در معامله', 'sold' => 'فروخته‌شده', 'withdrawn' => 'لغو توسط عرضه‌کننده', 'rejected' => 'رد‌شده', 'field_visit' => 'بازدید میدانی', 'teardown' => 'تفکیک فنی', 'priced' => 'قیمت‌گذاری‌شده', 'approved' => 'تأیید‌شده', 'negotiating' => 'در حال مذاکره', 'quoted' => 'پیش‌فاکتور', 'contracted' => 'قرارداد‌شده', 'in_progress' => 'در حال اجرا', 'completed' => 'تکمیل‌شده', 'cancelled' => 'لغو‌شده', 'pending' => 'در انتظار', 'accepted' => 'پذیرفته‌شده', 'declined' => 'رد‌شده', 'expired' => 'منقضی‌شده', 'paid' => 'پرداخت‌شده', ]; } public function statusLabel(?string $status): string { return $this->statusLabels()[$status] ?? ($status ?: '—'); } public function listingTypeLabels(): array { return [ 'machine_new' => 'ماشین نو', 'machine_used' => 'ماشین دست‌دوم', 'production_line_full' => 'خط تولید کامل', 'production_line_partial' => 'بخشی از خط تولید', 'subsystem' => 'زیرسیستم', 'spare_lot' => 'قطعات/لوازم', ]; } public function listingTypeLabel(?string $type): string { return $this->listingTypeLabels()[$type] ?? ($type ?: '—'); } public function dealTypeLabels(): array { return [ 'company_purchase' => 'خرید برای شرکت', 'brokerage' => 'واسطه‌گری', 'appraisal_only' => 'فقط کارشناسی', 'renovation_contract' => 'قرارداد نوسازی', 'consignment' => 'امانی', ]; } public function dealTypeLabel(?string $type): string { return $this->dealTypeLabels()[$type] ?? ($type ?: '—'); } }