booking = Booking::class; $this->enquiryClass = Enquiry::class; } protected function validateCheckout($code){ if(!is_enable_guest_checkout() and !Auth::check()){ return $this->sendError(__("You have to login in to do this"))->setStatusCode(401); } $booking = $this->booking::where('code', $code)->first(); $this->bookingInst = $booking; if (empty($booking)) { abort(404); } if (!is_enable_guest_checkout() and $booking->customer_id != Auth::id()) { abort(404); } return true; } public function checkout($code) { $res = $this->validateCheckout($code); if($res !== true) return $res; $booking = $this->bookingInst; if($booking->status != 'draft'){ return redirect('/'); } $is_api = request()->segment(1) == 'api'; $data = [ 'page_title' => __('Checkout'), 'booking' => $booking, 'service' => $booking->service, 'gateways' => $this->getGateways(), 'user' => Auth::user(), 'is_api' => $is_api ]; return view('Booking::frontend/checkout', $data); } public function checkStatusCheckout($code) { $booking = $this->booking::where('code', $code)->first(); $data = [ 'error' => false, 'message' => '', 'redirect' => '' ]; if (empty($booking)) { $data = [ 'error' => true, 'redirect' => url('/') ]; } if (!is_enable_guest_checkout() and $booking->customer_id != Auth::id()) { $data = [ 'error' => true, 'redirect' => url('/') ]; } if ($booking->status != 'draft') { $data = [ 'error' => true, 'redirect' => url('/') ]; } return response()->json($data, 200); } protected function validateDoCheckout(){ $request = \request(); if(!is_enable_guest_checkout() and !Auth::check()){ return $this->sendError(__("You have to login in to do this"))->setStatusCode(401); } if(Auth::user() && !Auth::user()->hasVerifiedEmail() && setting_item('enable_verify_email_register_user') == 1){ return $this->sendError(__("You have to verify email first"), ['url' => url('/email/verify')]); } /** * @param Booking $booking */ $validator = Validator::make($request->all(), [ 'code' => 'required', ]); if ($validator->fails()) { return $this->sendError('', ['errors' => $validator->errors()]); } $code = $request->input('code'); $booking = $this->booking::where('code', $code)->first(); $this->bookingInst = $booking; if (empty($booking)) { abort(404); } if (!is_enable_guest_checkout() and $booking->customer_id != Auth::id()) { abort(404); } return true; } public function doCheckout(Request $request) { /** * @var $booking Booking * @var $user User */ $res = $this->validateDoCheckout(); if($res !== true) return $res; $user = auth()->user(); $booking = $this->bookingInst; if ($booking->status != 'draft') { return $this->sendError('',[ 'url'=>$booking->getDetailUrl() ]); } $service = $booking->service; if (empty($service)) { return $this->sendError(__("Service not found")); } $is_api = request()->segment(1) == 'api'; /** * Google ReCapcha */ if(!$is_api and ReCaptchaEngine::isEnable() and setting_item("booking_enable_recaptcha")){ $codeCapcha = $request->input('g-recaptcha-response'); if(!$codeCapcha or !ReCaptchaEngine::verify($codeCapcha)){ return $this->sendError(__("Please verify the captcha")); } } $rules = [ 'first_name' => 'required|string|max:255', 'last_name' => 'required|string|max:255', 'email' => 'required|string|email|max:255', 'phone' => 'required|string|max:255', 'country' => 'required', 'term_conditions' => 'required', ]; $how_to_pay = $request->input('how_to_pay', ''); $credit = $request->input('credit', 0); $payment_gateway = $request->input('payment_gateway'); // require payment gateway except pay full if(empty(floatval($booking->deposit)) || $how_to_pay == 'deposit' || !auth()->check()){ $rules['payment_gateway'] = 'required'; } if(auth()->check()) { if ($credit > $user->balance) { return $this->sendError(__("Your credit balance is :amount", ['amount' => $user->balance])); } }else{ // force credit to 0 if not login $credit = 0; } $rules = $service->filterCheckoutValidate($request, $rules); if (!empty($rules)) { $messages = [ 'term_conditions.required' => __('Term conditions is required field'), 'payment_gateway.required' => __('Payment gateway is required field'), ]; $validator = Validator::make($request->all(), $rules , $messages ); if ($validator->fails()) { return $this->sendError('', ['errors' => $validator->errors()]); } } $wallet_total_used = credit_to_money($credit); if($wallet_total_used > $booking->total){ $credit = money_to_credit($booking->total,true); $wallet_total_used = $booking->total; } $service->beforeCheckout($request, $booking); // Normal Checkout $booking->first_name = $request->input('first_name'); $booking->last_name = $request->input('last_name'); $booking->email = $request->input('email'); $booking->phone = $request->input('phone'); $booking->address = $request->input('address_line_1'); $booking->address2 = $request->input('address_line_2'); $booking->city = $request->input('city'); $booking->state = $request->input('state'); $booking->zip_code = $request->input('zip_code'); $booking->country = $request->input('country'); $booking->customer_notes = $request->input('customer_notes'); $booking->gateway = $payment_gateway; $booking->wallet_credit_used = floatval($credit); $booking->wallet_total_used = floatval($wallet_total_used); $booking->pay_now = floatval($booking->deposit == null ? $booking->total : $booking->deposit); // If using credit if($booking->wallet_total_used > 0){ if($how_to_pay == 'full'){ $booking->deposit = 0; $booking->pay_now = $booking->total; }elseif($how_to_pay == 'deposit'){ // case guest input credit more than "pay deposit" need to pay // Ex : pay deposit 10$ but guest input 20$ -> minus credit balance = 10$ if($wallet_total_used > $booking->deposit){ $wallet_total_used = $booking->deposit; $booking->wallet_total_used = floatval($wallet_total_used); $booking->wallet_credit_used = money_to_credit($wallet_total_used,true); } } $booking->pay_now = max(0,$booking->pay_now - $wallet_total_used); $booking->paid = $booking->wallet_total_used; }else{ if($how_to_pay == 'full'){ $booking->deposit = 0; $booking->pay_now = $booking->total; } } $gateways = get_payment_gateways(); if($booking->pay_now > 0){ $gatewayObj = new $gateways[$payment_gateway]($payment_gateway); if (!empty($rules['payment_gateway'])) { if (empty($gateways[$payment_gateway]) or !class_exists($gateways[$payment_gateway])) { return $this->sendError(__("Payment gateway not found")); } if (!$gatewayObj->isAvailable()) { return $this->sendError(__("Payment gateway is not available")); } } } if($booking->wallet_credit_used && auth()->check()) { try { $transaction = $user->withdraw($booking->wallet_credit_used, [ 'wallet_total_used' => $booking->wallet_total_used ]); }catch (\Exception $exception){ return $this->sendError($exception->getMessage()); } $transaction->booking_id = $booking->id; $transaction->save(); $booking->wallet_transaction_id = $transaction->id; } $booking->save(); if(Auth::check()) { $user = Auth::user(); $user->first_name = $request->input('first_name'); $user->last_name = $request->input('last_name'); $user->phone = $request->input('phone'); $user->address = $request->input('address_line_1'); $user->address2 = $request->input('address_line_2'); $user->city = $request->input('city'); $user->state = $request->input('state'); $user->zip_code = $request->input('zip_code'); $user->country = $request->input('country'); $user->save(); } $booking->addMeta('locale',app()->getLocale()); $booking->addMeta('how_to_pay',$how_to_pay); $service->afterCheckout($request, $booking); if($booking->pay_now > 0) { try { $gatewayObj->process($request, $booking, $service); } catch (Exception $exception) { return $this->sendError($exception->getMessage()); } }else{ if($booking->paid < $booking->total){ $booking->status = $booking::PARTIAL_PAYMENT; }else{ $booking->status = $booking::PAID; } $booking->save(); event(new BookingCreatedEvent($booking)); return $this->sendSuccess( [ 'url'=>$booking->getDetailUrl() ], __("You payment has been processed successfully")); } } public function confirmPayment(Request $request, $gateway) { $gateways = get_payment_gateways(); if (empty($gateways[$gateway]) or !class_exists($gateways[$gateway])) { return $this->sendError(__("Payment gateway not found")); } $gatewayObj = new $gateways[$gateway]($gateway); if (!$gatewayObj->isAvailable()) { return $this->sendError(__("Payment gateway is not available")); } return $gatewayObj->confirmPayment($request); } public function cancelPayment(Request $request, $gateway) { $gateways = get_payment_gateways(); if (empty($gateways[$gateway]) or !class_exists($gateways[$gateway])) { return $this->sendError(__("Payment gateway not found")); } $gatewayObj = new $gateways[$gateway]($gateway); if (!$gatewayObj->isAvailable()) { return $this->sendError(__("Payment gateway is not available")); } return $gatewayObj->cancelPayment($request); } /** * @todo Handle Add To Cart Validate * * @param Request $request * @return string json */ public function addToCart(Request $request) { if(!is_enable_guest_checkout() and !Auth::check()){ return $this->sendError(__("You have to login in to do this"))->setStatusCode(401); } if(Auth::user() && !Auth::user()->hasVerifiedEmail() && setting_item('enable_verify_email_register_user')==1){ return $this->sendError(__("You have to verify email first"), ['url' => url('/email/verify')]); } $validator = Validator::make($request->all(), [ 'service_id' => 'required|integer', 'service_type' => 'required' ]); if ($validator->fails()) { return $this->sendError('', ['errors' => $validator->errors()]); } $service_type = $request->input('service_type'); $service_id = $request->input('service_id'); $allServices = get_bookable_services(); if (empty($allServices[$service_type])) { return $this->sendError(__('Service type not found')); } $module = $allServices[$service_type]; $service = $module::find($service_id); if (empty($service) or !is_subclass_of($service, '\\Modules\\Booking\\Models\\Bookable')) { return $this->sendError(__('Service not found')); } if (!$service->isBookable()) { return $this->sendError(__('Service is not bookable')); } if(Auth::id() == $service->create_user){ return $this->sendError(__('You cannot book your own service')); } return $service->addToCart($request); } public function getGateways() { $all = get_payment_gateways(); $res = []; foreach ($all as $k => $item) { if (class_exists($item)) { $obj = new $item($k); if ($obj->isAvailable()) { $res[$k] = $obj; } } } return $res; } public function detail(Request $request, $code) { if(!is_enable_guest_checkout() and !Auth::check()){ return $this->sendError(__("You have to login in to do this"))->setStatusCode(401); } $booking = Booking::where('code', $code)->first(); if (empty($booking)) { abort(404); } if ($booking->status == 'draft') { return redirect($booking->getCheckoutUrl()); } if (!is_enable_guest_checkout() and $booking->customer_id != Auth::id()) { abort(404); } $data = [ 'page_title' => __('Booking Details'), 'booking' => $booking, 'service' => $booking->service, ]; if ($booking->gateway) { $data['gateway'] = get_payment_gateway_obj($booking->gateway); } return view('Booking::frontend/detail', $data); } public function exportIcal($service_type = '', $id) { \Debugbar::disable(); $allServices = get_bookable_services(); if (empty($allServices[$service_type])) { return $this->sendError(__('Service type not found')); } $module = $allServices[$service_type]; $path ='/ical/'; $fileName = 'booking_' . $service_type . '_' . $id . '.ics'; $fullPath = $path.$fileName; $content = $this->booking::getContentCalendarIcal($service_type,$id,$module); Storage::disk('uploads')->put($fullPath, $content); $file = Storage::disk('uploads')->get($fullPath); header('Content-Type: text/calendar; charset=utf-8'); header('Content-Disposition: attachment; filename="' . $fileName . '"'); echo $file; } public function addEnquiry(Request $request){ $rules = [ 'service_id' => 'required|integer', 'service_type' => 'required', 'enquiry_name' => 'required', 'enquiry_email' => [ 'required', 'email', 'max:255', ], ]; $validator = Validator::make($request->all(),$rules); if ($validator->fails()) { return $this->sendError('', ['errors' => $validator->errors()]); } if(setting_item('booking_enquiry_enable_recaptcha')){ $codeCapcha = trim($request->input('g-recaptcha-response')); if(empty($codeCapcha) or !ReCaptchaEngine::verify($codeCapcha)){ return $this->sendError(__("Please verify the captcha")); } } $service_type = $request->input('service_type'); $service_id = $request->input('service_id'); $allServices = get_bookable_services(); if (empty($allServices[$service_type])) { return $this->sendError(__('Service type not found')); } $module = $allServices[$service_type]; $service = $module::find($service_id); if (empty($service) or !is_subclass_of($service, '\\Modules\\Booking\\Models\\Bookable')) { return $this->sendError(__('Service not found')); } $row = new $this->enquiryClass(); $row->fill([ 'name'=>$request->input('enquiry_name'), 'email'=>$request->input('enquiry_email'), 'phone'=>$request->input('enquiry_phone'), 'note'=>$request->input('enquiry_note'), ]); $row->object_id = $request->input("service_id"); $row->object_model = $request->input("service_type"); $row->status = "pending"; $row->vendor_id = $service->create_user; $row->save(); event(new EnquirySendEvent($row)); return $this->sendSuccess([ 'message' => __("Thank you for contacting us! We will be in contact shortly.") ]); } /** * @param Request $request * @return \Illuminate\Http\JsonResponse */ public function setPaidAmount(Request $request){ $rules = [ 'remain' => 'required|integer', 'id' => 'required' ]; $validator = Validator::make($request->all(),$rules); if ($validator->fails()) { return $this->sendError('', ['errors' => $validator->errors()]); } $id = $request->input('id'); $remain = floatval($request->input('remain')); if($remain < 0){ return $this->sendError(__('Remain can not smaller than 0')); } $booking = Booking::where('id', $id)->first(); if (empty($booking)) { return $this->sendError(__('Booking not found')); } $booking->pay_now = $remain; $booking->paid = floatval($booking->total) - $remain; event(new SetPaidAmountEvent($booking)); if($remain == 0){ $booking->status = $booking::PAID; event(new BookingUpdatedEvent($booking)); } $booking->save(); return $this->sendSuccess([ 'message' => __("You booking has been changed successfully") ]); } }