route('hosting.single-domain'); } public function show( Request $request, HostingOrder $hostingOrder, ResellerClubHostingService $hosting, ResellerClubProductService $products ): View { if ((int) $hostingOrder->user_id !== (int) $request->user()->id) { abort(403); } $remoteDetails = null; if ($hostingOrder->rc_order_id && $hosting->isConfigured()) { $result = $hosting->getOrderDetails($hostingOrder->rc_order_id); if ($result['success'] ?? false) { $remoteDetails = $result['order']; // Sync latest data $hosting->syncOrderToLocal($result['order']['raw'] ?? $result['order'], $request->user()->id, $hostingOrder->domain_id); $hostingOrder->refresh(); } } return view('hosting.show', [ 'order' => $hostingOrder, 'remoteDetails' => $remoteDetails, 'renewalOptions' => $this->renewalOptionsForOrder($hostingOrder, $products), ]); } public function sync( Request $request, ResellerClubHostingService $hosting, ResellerClubCustomerService $customers ): RedirectResponse { $user = $request->user(); if (! $hosting->isConfigured()) { return redirect()->route('hosting.index')->with('error', 'Hosting service is not configured.'); } $resolved = $customers->resolveCustomerForUser($user); if (! ($resolved['success'] ?? false)) { return redirect()->route('hosting.index') ->with('error', $resolved['message'] ?? 'Could not prepare your ResellerClub customer.'); } $synced = $hosting->syncCustomerOrders((string) $resolved['customer_id'], $user->id); return redirect()->route('hosting.index') ->with('success', "Synced {$synced} hosting order(s) from ResellerClub."); } public function order( Request $request, ResellerClubHostingService $hosting, ResellerClubCustomerService $customers ): JsonResponse { $request->validate([ 'domain_name' => 'required|string|max:253', 'plan_id' => 'required|string', 'months' => 'sometimes|integer|min:1|max:120', ]); if (! $hosting->isConfigured()) { return response()->json(['message' => 'Hosting service is not available at this time.'], 503); } $domainName = strtolower(trim($request->input('domain_name'))); $planId = $request->input('plan_id'); $months = $request->integer('months', 1); $resolved = $customers->resolveCustomerForUser($request->user()); if (! ($resolved['success'] ?? false)) { return response()->json([ 'message' => $resolved['message'] ?? 'Could not prepare your ResellerClub customer.', ], 422); } $result = $hosting->orderHosting($domainName, $planId, (string) $resolved['customer_id'], $months); if (! $result['success']) { return response()->json(['message' => $result['message'] ?? 'Hosting order failed.'], 422); } // Fetch details and save locally $order = null; if (! empty($result['order_id'])) { $details = $hosting->getOrderDetails($result['order_id']); if ($details['success'] ?? false) { $order = $hosting->syncOrderToLocal( $details['order']['raw'] ?? $details['order'], $request->user()->id ); } else { $order = HostingOrder::create([ 'user_id' => $request->user()->id, 'domain_name' => $domainName, 'rc_order_id' => $result['order_id'], 'plan_name' => $planId, 'status' => HostingOrder::STATUS_PENDING, ]); } } return response()->json([ 'success' => true, 'message' => 'Hosting order placed successfully.', 'order' => $order?->only('id', 'domain_name', 'status', 'rc_order_id'), ]); } public function resetPanelPassword(Request $request, HostingOrder $hostingOrder, ResellerClubHostingService $hosting): JsonResponse { if ((int) $hostingOrder->user_id !== (int) $request->user()->id) { abort(403); } $validated = $request->validate([ 'password' => ['required', 'string', 'min:9', 'max:16', 'regex:/^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)(?=.*[~*!@$#%_+.\?:,{}]).+$/'], ]); if (! $hosting->isConfigured() || ! $hostingOrder->rc_order_id) { return response()->json(['message' => 'Hosting service is not available.'], 503); } $result = $hosting->changePanelPassword($hostingOrder->rc_order_id, $validated['password']); if (! $result['success']) { return response()->json(['message' => $result['message'] ?? 'Could not update the cPanel password.'], 422); } return response()->json([ 'success' => true, 'message' => 'cPanel password updated successfully.', ]); } public function renew(Request $request, HostingOrder $hostingOrder, ResellerClubHostingService $hosting): JsonResponse { if ((int) $hostingOrder->user_id !== (int) $request->user()->id) { abort(403); } $request->validate([ 'months' => 'sometimes|integer|min:1|max:120', ]); if (! ResellerClubLegacy::renewalsEnabled()) { return response()->json(['message' => ResellerClubLegacy::renewalsDisabledMessage()], 503); } if (! $hosting->isConfigured() || ! $hostingOrder->rc_order_id) { return response()->json(['message' => 'Hosting service is not available.'], 503); } $result = $hosting->renewOrder($hostingOrder->rc_order_id, $request->integer('months', 1)); if (! $result['success']) { return response()->json(['message' => $result['message'] ?? 'Renewal failed.'], 422); } // Re-sync details $details = $hosting->getOrderDetails($hostingOrder->rc_order_id); if ($details['success'] ?? false) { $hosting->syncOrderToLocal($details['order']['raw'] ?? $details['order'], $request->user()->id, $hostingOrder->domain_id); } return response()->json(['success' => true, 'message' => 'Hosting renewed successfully.']); } public function destroy(Request $request, HostingOrder $hostingOrder, ResellerClubHostingService $hosting): RedirectResponse { if ((int) $hostingOrder->user_id !== (int) $request->user()->id) { abort(403); } if ($hostingOrder->status === HostingOrder::STATUS_CANCELLED) { $redirectRoute = $this->productRouteForOrder($hostingOrder); $hostingOrder->delete(); return redirect()->route($redirectRoute) ->with('success', 'Cancelled hosting order deleted.'); } if ($hostingOrder->rc_order_id && $hosting->isConfigured()) { $result = $hosting->deleteOrder($hostingOrder->rc_order_id); if (! $result['success']) { return redirect()->route('hosting.show', $hostingOrder) ->with('error', $result['message'] ?? 'Could not cancel hosting at this time.'); } } $hostingOrder->update(['status' => HostingOrder::STATUS_CANCELLED]); return redirect()->route($this->productRouteForOrder($hostingOrder)) ->with('success', 'Hosting order cancelled.'); } private function productRouteForOrder(HostingOrder $hostingOrder): string { return match ((string) $hostingOrder->hosting_type) { HostingOrder::TYPE_MULTI_DOMAIN => 'hosting.multi-domain', HostingOrder::TYPE_RESELLER => 'hosting.multi-domain', default => 'hosting.single-domain', }; } /** * @return array */ private function renewalOptionsForOrder(HostingOrder $hostingOrder, ResellerClubProductService $products): array { $category = match ((string) $hostingOrder->hosting_type) { HostingOrder::TYPE_MULTI_DOMAIN => 'multi-domain-hosting', HostingOrder::TYPE_RESELLER => 'reseller-hosting', default => 'single-domain-hosting', }; $packages = collect((array) ($products->formDefinition($category)['packages'] ?? [])); $planId = (string) ($hostingOrder->plan_id ?? ''); $planName = strtolower(trim((string) $hostingOrder->plan_name)); $package = $packages->first(function (array $item) use ($planId, $planName): bool { $value = (string) ($item['value'] ?? ''); $label = strtolower(trim((string) ($item['label'] ?? ''))); return ($planId !== '' && $value === $planId) || ($planName !== '' && $label !== '' && $label === $planName); }); if (! is_array($package)) { return collect(['1', '3', '6', '12', '24', '36']) ->map(fn (string $months) => [ 'months' => $months, 'label' => $months.' '.((int) $months === 1 ? 'Month' : 'Months'), 'total' => null, 'monthly' => null, ]) ->all(); } $priceField = ! empty((array) ($package['renew_prices'] ?? [])) ? 'renew_prices' : 'prices'; $totalField = ! empty((array) ($package['renew_totals'] ?? [])) ? 'renew_totals' : 'totals'; return collect(array_keys((array) ($package[$priceField] ?? []))) ->sortBy(fn (string $months) => (int) $months) ->values() ->map(fn (string $months) => [ 'months' => $months, 'label' => $months.' '.((int) $months === 1 ? 'Month' : 'Months'), 'total' => (string) (($package[$totalField][$months] ?? null) ?: ''), 'monthly' => (string) (($package[$priceField][$months] ?? null) ?: ''), ]) ->all(); } }