Sh3ll
OdayForums


Server : Apache
System : Linux 145.162.205.92.host.secureserver.net 5.14.0-611.45.1.el9_7.x86_64 #1 SMP PREEMPT_DYNAMIC Wed Apr 1 05:56:53 EDT 2026 x86_64
User : tradze ( 1001)
PHP Version : 8.1.34
Disable Function : NONE
Directory :  /home/tradze/www/app/Modules/Users/Http/Controllers/Api/

Upload File :
current_dir [ Writeable ] document_root [ Writeable ]

 

Current File : /home/tradze/www/app/Modules/Users/Http/Controllers/Api/ApiBasketController.php
<?php

namespace App\Modules\Users\Http\Controllers\Api;

use App\Events\ApiOverdueBasketEvent;
use App\Events\ApiResetBasketEvent;
use App\Events\CheckExtensionBasketEvent;
use App\Http\Controllers\ApiController;
use App\Modules\Banners\Repositories\BannersRepo;
use App\Modules\Invoices\Repositories\BookingInvoiceRepository;
use App\Modules\Notifications\Facades\NotifRepository;
use App\Modules\Postcodes\Models\TransportCost;
use App\Modules\Schedules\Models\BasketTherapist;
use App\Modules\Schedules\Models\BasketVoucher;
use App\Modules\Schedules\Models\BookingOrder;
use App\Modules\Schedules\Models\Order;
use App\Modules\Schedules\Repositories\BookingRepository;
use App\Modules\Services\Models\FocalPoint;
use App\Modules\Services\Models\ServiceDuration;
use App\Modules\Services\Models\SalonCategory;
use App\Modules\Services\Models\ServiceType;
use App\Modules\Postcodes\Models\Postcode;
use App\Modules\Vouchers\Repositories\VoucherRepository;
use App\User;
use App\PendingPayment;
//use Braintree\ClientToken;
use Carbon\Carbon;
use Darryldecode\Cart\Cart;
use Darryldecode\Cart\CartCondition;
use Illuminate\Console\Scheduling\Event;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\DB;
use Mail;
use Illuminate\Support\Facades\Session;
use Illuminate\Support\Facades\Storage;
use Illuminate\Http\Request;
use Laracasts\Flash\Flash;
use Mockery\CountValidator\Exception;
use Omnipay\Common\CreditCard;
use Omnipay\Omnipay;
use App\Modules\Users\Models\UserCoverageArea;
use App\Modules\Users\Models\UserServiceDuration;
use App\Modules\Schedules\Models\DynamicPricing;
use Illuminate\Support\Facades\Http;
use Illuminate\Support\Str;

class ApiBasketController extends ApiController
{

    /**
     * The book repository instance
     *
     * @var BookingRepository
     */
    protected $book;
    protected $ttl;
    protected $order_table_hours_limit;

    /**
     * Create a new controller instance.
     */
    public function __construct(BannersRepo $banners, BookingRepository $book)
    {
        parent::__construct($banners);
        $this->book = $book;

        //time to live item basket: in minutes
        $this->ttl = 5;

        //user can order table only if the booking will be over x hours. for more flexibility and accuracy, the value is in seconds
        $this->order_table_hours_limit = 86400;
    }

    /**
     * Add items in basket
     * @param int $checkout
     * @return \Illuminate\Contracts\Routing\ResponseFactory|\Symfony\Component\HttpFoundation\Response
     */
    public function add(Request $request, $checkout = 0)
    {
        \Cart::clear();

        // Delete every row that matches that therapist_id
        // BasketTherapist::where('therapist_id', $request->selected_therapists[0])->delete();
        // dd('here');

        $count = BasketTherapist::where('therapist_id', $request->selected_therapists[0])
            ->where('duration_id', $request->duration)
            ->where('date', $request->date)
            ->where('hour', $request->hour)
            ->where('reserved_until', '>=', Carbon::now())
            ->count();

        if ($count > 0) {
            $userBasketCount = BasketTherapist::where('therapist_id', $request->selected_therapists[0])
                ->where('duration_id', $request->duration)
                ->where('date', $request->date)
                ->where('hour', $request->hour)
                ->where('reserved_until', '>=', Carbon::now())
                ->where('user_id', $this->user->id)
                ->count();
            if ($userBasketCount > 0) {
                return response([
                    'success' => true,
                    'message' => 'This therapists is already in cart',
                ], 200);
            } else {
                return response([
                    'success' => true,
                    'message' => "Someone else just booked this therapist",
                ], 200);
            }
        }
        //first clear basket session tables for overdue items

        // \Event::fire(new ApiOverdueBasketEvent());

        //get booking data from session
        // Session::forget('booking');
        $booking = (array) Session::get('booking');
        $booking['postcode'] = $request->postcode;
        $booking['address'] = $request->address;
        $booking['date'] = $request->date;
        $booking['hour'] = $request->hour;
        $booking['massage'] = $request->massage;
        $booking['duration'] = $request->duration;
        $booking['therapists_opt'] = $request->therapists_opt;
        $booking['selected_therapists'] = $request->selected_therapists;

        Session::put('booking', $booking);

        $duration = ServiceDuration::where('id', $booking['duration'])->first();
        $massage_type = ServiceType::where('id', $booking['massage'])->first();
        if(empty($duration)){
            return response([
                'success' => false,
                'message' => 'Invalid duration.',
            ], 400);
        }

        if(empty($massage_type)){
            return response([
                'success' => false,
                'message' => 'Invalid service type or service unavailable.',
            ], 400);
        }

        // \Cart::clear();

        //        return response([
        //            'success'=>false,
        //            'message'=>null,
        //            'items'=>[],
        //            'total'=>\Cart::getTotal(),
        //            'session'=> $request->session()->getId(),
        //        ],200);

        BasketVoucher::where('session_id', $request->session()->getId())->delete();
        BasketTherapist::where('session_id', $request->session()->getId())->delete();

        switch ($request->therapists_opt) {
            case '1_th':
                $therapists = 1;
                $type = '1 therapist';
                break;
            case '2_th':
                $therapists = 2;
                $type = '2 therapists';
                break;
            case '4hands':
                $therapists = 2;
                $type = 'four hands massage';
                break;
        } //end switch

        $booking['therapists_opt'] = $request->therapists_opt;
        $booking['therapists'] = $therapists;
        $booking['type'] = $type;

        unset($booking['selected_therapists']);

        if (count($request->selected_therapists)) {
            foreach ($request->selected_therapists as $th) {
                if (is_array($th))
                    $booking['selected_therapists'][] = $th['id'];
                else
                    $booking['selected_therapists'][] = $th;
            } //endoreach
        }
        // $booking['selected_therapists'] = $request->selected_therapists;

        Session::put('booking', $booking);

        $mandatory_fields = ['postcode', 'duration', 'massage', 'date', 'hour', 'selected_therapists'];
        foreach ($mandatory_fields as $field) {
            if (!isset($booking[$field])) {

                //              return response([$booking,$field],200);
                //return booking data
                return response([
                    'success' => false,
                    'message' => 'You must select the postcode, massage duration, type of massage, date of massage, desired hour and the therapist',
                ], 200);
            }
        } //endforeach
        //add to basket
        switch ($booking['therapists_opt']) {
            case '2_th': {
                    $this->add_therapists($booking);
                    break;
                }
            case '4hands': {
                    $this->add_therapists($booking);
                    break;
                }
            default: {
                    $test = $this->add_single($booking);
                    break;
                }
        } //end switch

        // $vatData = DB::select("SELECT value FROM taxes WHERE id = :id LIMIT 1", ['id' => 2]);
        // $vat = $vatData[0]->value;

        // $cartTotal = \Cart::getTotal();
        // $vatAmount = ($cartTotal * ($vat / 100));
        // $cartTotalAmt =  $cartTotal + $vatAmount;
        // dd($items);
        $items = \Cart::getContent();

        foreach ($items as $item) {
            $disclaimer = (!$item->attributes['can_order_table']) ? trans('schedules::booking.mobile_massage_table_24_notice') : '';
            if ($item->attributes['has_table_by_default']) {
                $disclaimer = $item->attributes['can_order_table_info'];
            }
            $data[] = [
                'id' => $item->id,
                'price' => number_format(ceil($item->getPriceSum() * 20) / 20, 2),
                'total' => number_format(ceil($item->getPriceSumWithConditions() * 20) / 20, 2),
                'service_price' => number_format(ceil($item->attributes['service_price'] * 20) / 20, 2),
                // 'total' => $cartTotalAmt,
                'reserved_until' => $item->attributes['reserved_until'],
                'can_order_table' => $item->attributes['can_order_table'],
                'has_table' => $item->attributes['has_table'],
                'table_price' => env('TABLE_VALUE', 9.99),
                'disclaimer' => $disclaimer,
                'has_transport' => number_format(ceil($item->attributes['has_transport'] * 20) / 20, 2),
                'transport_cost' => number_format(ceil($item->attributes['transport_cost'] * 20) / 20, 2),
                'itemInfo' => $item,
                'vat_amount' => number_format(round($item->attributes['vat_amount'], 2), 2, '.', '')
            ];
        } //endforeach

        //return booking session data
        return response([
            'success' => true,
            'message' => null,
            'latest_item_id' => $test,
            'items' => $data,
            // 'total'=> $cartTotalAmt,
            'total' => number_format(ceil(\Cart::getTotal() * 20) / 20, 2),
            'session' => $request->session()->getId(),
            'cart1' => \Cart::getContent(),
        ], 200);
    }

    /**
     * Get cart content
     * @return \Illuminate\Contracts\Routing\ResponseFactory|\Symfony\Component\HttpFoundation\Response
     */
    public function getcart()
    {
        return response([
            'success' => true,
            'cart' => \Cart::getContent(),
        ], 200);
    }

    /**
     * Add item in basket for single massage option
     * @param $booking
     */
    protected function add_single($booking)
    {
        $therapists = $this->book->selected_therapists();
        // $therapists = User::whereIn('id',$booking['selected_therapists'])->get();

        $duration = ServiceDuration::where('id', $booking['duration'])->first();

        $massage_type = ServiceType::where('id', $booking['massage'])->first();

        $quantity = $booking['therapists'];

        $dayKey = Carbon::parse($booking['date'])->dayOfWeekIso; // 1 = Monday, 7 = Sunday

        // Dynamic pricing applied
        $defaultPrice = DynamicPricing::where('day_of_week', 0)
            ->first();

        $time = $booking['hour'];
        $matched = DynamicPricing::where('type', 'TIMESLOT')
            ->where('day_of_week', $dayKey)
            ->whereTime('time_start', '<=', $time)
            ->whereTime('time_end', '>=', $time)
            ->first();

        $defaultPriceValue = (float) ($defaultPrice->price ?? 0);

        $price = (float) ($matched->price ?? $defaultPriceValue);
        $commision_co = (float) ($matched->tradze_co ?? $defaultPrice->tradze_co ?? 0);
        $commision_th = (float) ($matched->provider_co ?? $defaultPrice->provider_co ?? 0);

        // $bookingDuration = UserServiceDuration::where('services_duration_id', $booking['duration'])
        //     ->where('user_id', $therapists[0]->id)
        //     ->first();
        // if (!$bookingDuration) {
        //     $price =  $duration->price;
        // } else {
        //     $price = $bookingDuration->price;
        // }

        $vatData = DB::select("SELECT value FROM taxes WHERE id = :id LIMIT 1", ['id' => 2]);
        $vat = isset($vatData[0]) ? (float) $vatData[0]->value : 0; // % (can be 0)
        $cartTotal = (float) $price;
        $vatAmount = $vat > 0 ? ($cartTotal * $vat) / 100 : 0;
        $cartTotalAmt =  $cartTotal + $vatAmount;

        // $price = $duration->price;

        foreach ($therapists as $addth) {
            $names[] = $addth->name;
            $images[] = $addth->avatar_url;
            $thIds[] = $addth->id;
            break;
        } //end foreach
        //get geo-location with google places
        $googlePlaces = $this->getGeoLocation($booking['postcode']);

        //get focal points
        $focal_points_string = $this->getFocalPoints($booking);

        foreach ($therapists as $therapist) {

            // if ($therapist->services_commisions) {
            //     if (isset($therapist->services_commisions[$duration->id])) {
            //         $commision_co = $therapist->services_commisions[$duration->id]['commision_co'];
            //         $commision_th = $therapist->services_commisions[$duration->id]['commision_th'];
            //     } else {
            //         $commision_co = $duration->commision_co;
            //         $commision_th = $duration->commision_th;
            //     }
            // } else {
            //     $commision_co = $duration->commision_co;
            //     $commision_th = $duration->commision_th;
            // }

            $commision_co = (float) ($matched->tradze_co ?? $defaultPrice->tradze_co ?? 0);
            $commision_th = (float) ($matched->provider_co ?? $defaultPrice->provider_co ?? 0);
            $commision_perentage = (float) ($matched->percentage ?? $defaultPrice->percentage ?? 0);

            $can_order_table = $this->can_order_table($booking);
            $can_order_table_info = $this->can_order_table($booking) ? '' : trans('schedules::booking.massage_table_24_notice');

            if ($therapist->has_massage_table) {
                $can_order_table = false;
                $can_order_table_info = trans('schedules::booking.massage_table_is_included');
            }

            $itemId = Str::random(10);
            $item = [
                'id' => $itemId,
                'name' => $massage_type->name,
                // 'price' => $price,
                'price' => $cartTotalAmt,
                'vat_amount' => $vatAmount,
                'quantity' => $quantity,
                'attributes' => array(
                    'reserved_until' => Carbon::now()->addMinutes($this->ttl)->format('Y-m-d H:i:s'),
                    'therapist' => $names,
                    'therapistIds' => $thIds,
                    'therapistImage' => $images,
                    'therapistsNo' => $booking['therapists'],
                    'therapistsOpt' => $booking['therapists_opt'],
                    'type' => $booking['type'],
                    'date' => Carbon::createFromFormat('Y-m-d', $booking['date'])->format('d M Y'),
                    'hour' => $booking['hour'],
                    'duration' => $duration->name,
                    'duration_min' => $duration->duration,
                    'duration_id' => $duration->id,
                    'service_price' => $cartTotal,
                    'vat_amount' => $vatAmount,
                    'duration_commision' => [
                        'company' => $commision_co,
                        'therapist' => $commision_th,
                        'company_commision_percent' => $commision_perentage,
                    ],
                    'massage_type' => $massage_type->name,
                    'massage_type_id' => $massage_type->id,
                    'focal_points' => $focal_points_string,
                    'can_order_table' => $can_order_table,
                    'can_order_table_info' => $can_order_table_info,
                    'disclaimer' => $this->disclaimer_info($booking),
                    'has_table' => false,
                    'has_table_by_default' => $therapist->has_massage_table,
                    'has_transport' => false,
                    'transport_cost' => 0,
                    'has_voucher' => false,
                    'user_name' => \Auth::check() ? \Auth::user()->name : '',
                    'user_phone' => \Auth::check() ? \Auth::user()->profile->mobile_number : '',
                    'address' => $booking['address'],
                    'postcode' => $booking['postcode'],
                    'county' => 'London',
                    'location' => $googlePlaces['formatted_address'],
                    'locationGeo' => $googlePlaces['geometry']['location'],
                    'notes' => '',
                    'vat_amount' => $vatAmount,
                ),
            ];

            // \Cart::add($item);
            // $userId = \Auth::check() ? \Auth::user()->id : 0;
            \Cart::add($item);
            $this->calc_transport_condition($booking, $itemId);

            //add to session basket
            $sesBasket = [
                'basket_item_id' => $itemId,
                'session_id' => request()->session()->getId(),
                'user_id' => $this->user->id,
                'therapist_id' => $therapist->id,
                'reserved_until' => $item['attributes']['reserved_until'],
                'date' => Carbon::createFromFormat('Y-m-d', $booking['date'])->format('Y-m-d'),
                'hour' => $item['attributes']['hour'],
                'duration' => $item['attributes']['duration'],
                'duration_min' => $item['attributes']['duration_min'],
                'duration_id' => $item['attributes']['duration_id'],
            ];

            BasketTherapist::create($sesBasket);
            // dd($therapist->has_massage_table);
            if ($therapist->has_massage_table) {
                $this->add_table_default($itemId);
            }
        } //endforeach
        //unset session booking
        Session::forget('booking');

        return $itemId;
    }

    /**
     * Add items in basket for 2 therapists massage option
     * @param $booking
     */
    protected function add_therapists($booking)
    {
        return $booking;
        $therapists = $this->book->selected_therapists();
        $duration = ServiceDuration::where('id', $booking['duration'])->first();
        $massage_type = ServiceType::where('id', $booking['massage'])->first();

        $quantity = 1;
        $price = $duration->price;

        foreach ($therapists as $addth) {
            $names[] = $addth->name;
            $images[] = $addth->avatar_url;
            $thIds[] = $addth->id;
        } //end foreach
        //get geo-location with google places
        $googlePlaces = $this->getGeoLocation($booking['postcode']);

        //get focal points
        $focal_points_string = $this->getFocalPoints($booking);

        foreach ($therapists as $therapist) {
            $itemId = str_random(10);

            if ($therapist->services_commisions) {
                if (isset($therapist->services_commisions[$duration->id])) {
                    $commision_co = $therapist->services_commisions[$duration->id]['commision_co'];
                    $commision_th = $therapist->services_commisions[$duration->id]['commision_th'];
                } else {
                    $commision_co = $duration->commision_co;
                    $commision_th = $duration->commision_th;
                }
            } else {
                $commision_co = $duration->commision_co;
                $commision_th = $duration->commision_th;
            }

            $can_order_table = $this->can_order_table($booking);
            $can_order_table_info = $this->can_order_table($booking) ? '' : trans('schedules::booking.massage_table_24_notice');

            if ($therapist->has_massage_table) {
                $can_order_table = false;
                $can_order_table_info = trans('schedules::booking.massage_table_is_included');
            }

            $item = [
                'id' => $itemId,
                'name' => $massage_type->name,
                'price' => $price,
                'quantity' => $quantity,
                'attributes' => array(
                    'reserved_until' => Carbon::now()->addMinutes($this->ttl)->format('Y-m-d H:i:s'),
                    'therapist' => [$therapist->name],
                    'therapistIds' => [$therapist->id],
                    'therapistImage' => [$therapist->avatar_url],
                    'therapistsNo' => $booking['therapists'],
                    'therapistsOpt' => $booking['therapists_opt'],
                    'type' => $booking['type'],
                    'date' => Carbon::createFromFormat('Y-m-d', $booking['date'])->format('d M Y'),
                    'hour' => $booking['hour'],
                    'duration' => $duration->name,
                    'duration_min' => $duration->duration,
                    'duration_id' => $duration->id,
                    'duration_commision' => [
                        'company' => $commision_co,
                        'therapist' => $commision_th,
                    ],
                    'massage_type' => $massage_type->name,
                    'massage_type_id' => $massage_type->id,
                    'focal_points' => $focal_points_string,
                    'has_table' => false,
                    'has_table_by_default' => $therapist->has_massage_table,
                    'can_order_table' => $can_order_table,
                    'can_order_table_info' => $can_order_table_info,
                    'disclaimer' => $this->disclaimer_info($booking),
                    'has_transport' => false,
                    'transport_cost' => 0,
                    'has_voucher' => false,
                    'user_name' => \Auth::check() ? \Auth::user()->name : '',
                    'user_phone' => \Auth::check() ? \Auth::user()->profile->mobile_number : '',
                    'address' => $booking['address'],
                    'postcode' => $booking['postcode'],
                    'county' => 'London',
                    'location' => $booking['address'],
                    'locationGeo' => $googlePlaces['geometry']['location'],
                    'notes' => '',
                ),
            ];
            \Cart::add($item);
            $this->calc_transport_condition($booking, $itemId);

            //add to session basket
            $sesBasket = [
                'basket_item_id' => $itemId,
                'session_id' => request()->session()->getId(),
                'user_id' => \Auth::check() ? \Auth::user()->id : '',
                'therapist_id' => $therapist->id,
                'reserved_until' => $item['attributes']['reserved_until'],
                'date' => Carbon::createFromFormat('Y-m-d', $booking['date'])->format('Y-m-d'),
                'hour' => $item['attributes']['hour'],
                'duration' => $item['attributes']['duration'],
                'duration_min' => $item['attributes']['duration_min'],
                'duration_id' => $item['attributes']['duration_id'],
            ];
            BasketTherapist::create($sesBasket);

            if ($therapist->has_massage_table) {
                $this->add_table_default($itemId);
            }
        } //endforeach
        //unset session booking
        Session::forget('booking');
    }

    /**
     * Add item in baset for the 4hands massage option
     * @param $booking
     */
    protected function add_4hands($booking)
    {

        $therapists = $this->book->selected_therapists();
        $duration = ServiceDuration::where('id', $booking['duration'])->first();
        $massage_type = ServiceType::where('id', $booking['massage'])->first();

        $quantity = 1;
        $price = $duration->price * 2;

        foreach ($therapists as $addth) {
            $names[] = $addth->name;
            $images[] = $addth->avatar_url;
            $thIds[] = $addth->id;
        } //end foreach
        //get geo-location with google places
        $googlePlaces = $this->getGeoLocation($booking['postcode']);

        //get focal points
        $focal_points_string = $this->getFocalPoints($booking);

        $itemId = str_random(10);
        $item = [
            'id' => $itemId,
            'name' => $massage_type->name,
            'price' => $price,
            'quantity' => $quantity,
            'attributes' => array(
                'reserved_until' => Carbon::now()->addMinutes($this->ttl)->format('Y-m-d H:i:s'),
                'therapist' => $names,
                'therapistIds' => $thIds,
                'therapistImage' => $images,
                'therapistsNo' => $booking['therapists'],
                'therapistsOpt' => $booking['therapists_opt'],
                'type' => $booking['type'],
                'date' => Carbon::createFromFormat('Y-m-d', $booking['date'])->format('d M Y'),
                'hour' => $booking['hour'],
                'duration' => $duration->name,
                'duration_min' => $duration->duration,
                'duration_id' => $duration->id,
                'duration_commision' => [
                    'company' => $duration->commision_co,
                    'therapist' => $duration->commision_th,
                ],
                'massage_type' => $massage_type->name,
                'massage_type_id' => $massage_type->id,
                'focal_points' => $focal_points_string,
                'can_order_table' => $this->can_order_table($booking),
                'can_order_table_info' => $this->can_order_table($booking) ? '' : trans('schedules::booking.massage_table_24_notice'),
                'disclaimer' => $this->disclaimer_info($booking),
                'has_table' => false,
                'has_transport' => false,
                'transport_cost' => 0,
                'has_voucher' => false,
                'user_name' => \Auth::check() ? \Auth::user()->name : '',
                'user_phone' => \Auth::check() ? \Auth::user()->profile->mobile_number : '',
                'address' => $booking['address'],
                'postcode' => $booking['postcode'],
                'county' => 'London',
                'location' => $booking['address'],
                'locationGeo' => $googlePlaces['geometry']['location'],
                'notes' => '',
            ),
        ];
        \Cart::add($item);
        $this->calc_transport_condition($booking, $itemId);

        //add to session basket
        foreach ($therapists as $therapist) {
            $sesBasket = [
                'basket_item_id' => $itemId,
                'session_id' => request()->session()->getId(),
                'user_id' => \Auth::check() ? \Auth::user()->id : '',
                'therapist_id' => $therapist->id,
                'reserved_until' => $item['attributes']['reserved_until'],
                'date' => Carbon::createFromFormat('Y-m-d', $booking['date'])->format('Y-m-d'),
                'hour' => $item['attributes']['hour'],
                'duration' => $item['attributes']['duration'],
                'duration_min' => $item['attributes']['duration_min'],
                'duration_id' => $item['attributes']['duration_id'],
            ];
            BasketTherapist::create($sesBasket);
        } //end foreach
        //unset session booking
        Session::forget('booking');
    }

    /**
     * Add item in basket for single massage option
     * @param $booking
     */
    public function extend_booking_check(BookingOrder $booking, ServiceDuration $extension)
    {

        //set default response message
        $response = ['message' => trans('schedules::booking.message_error_extension_overlap')];

        //validate the booking and the extension
        //the booking must be owned by
        if ($booking->user_id != $this->user->id || !$booking || !$extension) {
            $response['message'] = trans('schedules::booking.message_error_extension_access_denied');
            return response($response, 403);
        } //endif
        //check extension availability
        $can_extend = $this->book->can_extend_with($booking, $extension);

        //if cant extend, return response
        if (!$can_extend)
            return response($response, 403);

        //create extension ttl
        $ttl_min = 1;
        $reservedDateLimit = Carbon::now()->addMinutes($ttl_min);

        //add to session
        $extensionProduct = [
            'id' => 'extension_' . $booking->id,
            'name' => $extension->name,
            'price' => $extension->price,
            'quantity' => 1,
            'attributes' => [
                'booking_id' => $booking->id,
                'booking_obj' => $booking,
                'duration' => $extension->name,
                'duration_min' => $extension->duration,
                'duration_id' => $extension->id,
                'duration_commision' => [
                    'commision_co' => $extension->commision_co,
                    'commision_th' => $extension->commision_th,
                ],
                'reserved_until' => $reservedDateLimit->format('Y-m-d H:i:s'),
            ]
        ];

        $cartID = 'extension_' . $booking->id;
        $cart = app('cart_extension');

        //delete from extension basket the therapists and extension service
        $sesExtBasket = BasketTherapist::where('session_id', request()->session()->getId())->delete();
        $cart->clear();

        //add extension service to cart
        $cart->add($extensionProduct);

        //add extension to the session_therapist_basket
        foreach ($booking->therapists as $therapist) {
            //add basket session table
            $sesBasket = [
                'basket_item_id' => $cartID,
                'session_id' => request()->session()->getId(),
                'user_id' => $this->user->id,
                'therapist_id' => $therapist->id,
                'reserved_until' => $reservedDateLimit->format('Y-m-d H:i:s'),
                'date' => $booking->date->format('Y-m-d'),
                'hour' => Carbon::createFromFormat('H:i', $booking->hour)->addMinutes($booking->duration_min)->format('H:i'),
                'duration' => $extension->name,
                'duration_min' => $extension->duration,
                'duration_id' => $extension->id,
            ];
            BasketTherapist::create($sesBasket);
        } //endforeach
        //return response
        return response(['message' => 'You can extend your booking. You have ' . $ttl_min . ' minutes to confirm your extension. Hurry up!'], 200);
    }

    /**
     * Determine if user can order table. This method is used to compute item basket attribute names can_order_table
     * @param $booking
     * @return bool
     */
    protected function can_order_table($booking)
    {
        //default value is false
        $status = false;

        //transform booking hour and time in carbon date-time format
        $datehour = Carbon::createFromFormat('Y-m-d H:i', $booking['date'] . " " . $booking['hour']);

        //calculate difference with current time
        $diff = Carbon::now()->diffInSeconds($datehour, false);

        //set status value
        if ($diff < $this->order_table_hours_limit)
            $status = false;
        else
            $status = true;

        //return status
        return $status;
    }

    /**
     * Checkout disclaimer
     * @param $booking
     * @return null|string|\Symfony\Component\Translation\TranslatorInterface
     */
    protected function disclaimer_info($booking)
    {
        $status = null;
        if (!isset($booking['disclaimer']))
            return $status;

        switch ($booking['disclaimer']) {
            case 'now':
                $status = trans('schedules::booking.message_disclaimer_massagemenow');
                break;
        } //endswitch
        //return status disclaimer
        return $status;
    }

    /**
     * Get google location based on user postcode
     * @param $booking
     * @return mixed
     */
    protected function getGeoLocation($postcode)
    {
        //        $response = \GoogleMaps::load('textsearch')
        //            ->setParam([
        //                'query' => "{$postcode} London UK",
        //            ])->get('results'); // return $this

        $response = \GoogleMaps::load('geocoding')
            ->setParam(['address' => "{$postcode} London UK"])
            ->get('results');

        if ($response['results'])
            $geoLocation = $response['results'][0];
        else
            $geoLocation = null;

        //return geolocation
        return $geoLocation;
    }

    /**
     * Get focal points for basket booking
     * @param $booking
     * @return string
     */
    protected function getFocalPoints($booking)
    {
        if (!isset($booking['focal_points']))
            $booking['focal_points'] = [];

        $objfp = FocalPoint::select('name')->whereIn('id', $booking['focal_points'])->get();

        $focal_points = [];
        foreach ($objfp as $fp)
            $focal_points[] = $fp->name;

        $response = implode(' / ', $focal_points);

        //return response
        return $response;
    }

    // New Transport cost logic
    public function calc_transport_condition($booking, $productID)
    {
        $item = \Cart::get($productID);
        $cost = 0;

        $polygons = DB::table('global_travel_cost')->orderBy('polygon_no')->get();

        if (empty($booking['address'])) return;

        $formattedAddr = str_replace(' ', '+', $booking['address']);

        // Using Laravel HTTP Client instead of file_get_contents
        $response = Http::get('https://maps.googleapis.com/maps/api/geocode/json', [
            'address' => $formattedAddr,
            'key' => config("googlemaps.key")
        ]);

        if (!$response->successful()) return;

        $geo = $response->json();

        if (empty($geo['results'][0]['geometry']['location'])) return;

        $addr_latitude = floatval($geo['results'][0]['geometry']['location']['lat']);
        $addr_longitude = floatval($geo['results'][0]['geometry']['location']['lng']);

        // Group polygons
        $polygons_grouped = [];
        foreach ($polygons as $p) {
            $polygons_grouped[$p->polygon_no][] = [
                'lat' => floatval($p->lat),
                'lng' => floatval($p->lng),
                'price' => floatval($p->price)
            ];
        }

        // Ray Casting
        $pointInPolygon = function ($point, $polygon) {
            $x = $point['lng'];
            $y = $point['lat'];
            $inside = false;
            $n = count($polygon);

            for ($i = 0, $j = $n - 1; $i < $n; $j = $i++) {
                $xi = $polygon[$i]['lng'];
                $yi = $polygon[$i]['lat'];
                $xj = $polygon[$j]['lng'];
                $yj = $polygon[$j]['lat'];

                $intersect = (($yi > $y) != ($yj > $y)) &&
                    ($x < ($xj - $xi) * ($y - $yi) / ($yj - $yi + 1e-10) + $xi);

                if ($intersect) $inside = !$inside;
            }

            return $inside;
        };

        foreach ($polygons_grouped as $polygon_no => $points) {
            if ($pointInPolygon(['lat' => $addr_latitude, 'lng' => $addr_longitude], $points)) {
                $cost = $points[0]['price'];
                break;
            }
        }

        if (!$cost) return;

        $costValue = $item->quantity > 1 ? $cost / 2 : $cost;

        \Cart::addItemCondition($productID, new CartCondition([
            'name' => 'Travel supplements',
            'type' => 'cost',
            'target' => 'item',
            'value' => $costValue,
            'order' => 3,
        ]));

        $attributes = $item->attributes;
        $attributes['has_transport'] = true;
        $attributes['transport_cost'] = $cost;

        \Cart::update($productID, ['attributes' => $attributes]);
    }

    /**
     * Update item id info
     * @param Request $request
     */
    public function update(Request $request)
    {
        //get input request
        $i = $request->all();

        //all fields must be set
        if (!$i['name'] || !$i['itemId'])
            return response(['message' => "not allowed"], 403);

        //allow only fields
        $allowed_names = ['user_name', 'user_phone', 'address', 'notes', 'county'];
        if (!in_array($i['name'], $allowed_names))
            return response(['message' => "not allowed"], 403);

        //get item cart and update value
        $item = \Cart::get($i['itemId']);
        $attributes = $item->attributes;
        $attributes[$i['name']] = $i['value'];
        \Cart::update($i['itemId'], array('attributes' => $attributes));

        //return success
        return response(['success' => true], 200);
    }

    /**
     * Remove item from basket
     * @param Request $request
     */
    public function cancel(Request $request)
    {
        $productID = $request->itemId;

        //remove item from cart
        \Cart::remove($productID);

        //delete all basket from session tables
        $session_id = $request->session()->getId();

        $sesTh = BasketTherapist::where('session_id', $session_id)
            ->where('basket_item_id', $productID)
            ->get();
        if ($sesTh) {
            foreach ($sesTh as $sth)
                $sth->delete();
        } //endif

        $sesCodes = BasketVoucher::where('session_id', $session_id)
            ->where('basket_item_id', $productID)
            ->get();
        if ($sesCodes) {
            foreach ($sesCodes as $scode)
                $scode->delete();
        } //endif
        //return response
        return response('success', 200);
    }

    /**
     * Clear basket
     * @param Request $request
     * @return \Illuminate\Contracts\Routing\ResponseFactory|\Symfony\Component\HttpFoundation\Response
     */
    public function cancel_all(Request $request)
    {

        //clear basket
        \Cart::clear();

        //delete all basket from session tables
        $session_id = $request->session()->getId();

        $sesTh = BasketTherapist::where('session_id', $session_id)->get();
        if ($sesTh) {
            foreach ($sesTh as $sth)
                $sth->delete();
        } //endif

        $sesCodes = BasketVoucher::where('session_id', $session_id)->get();
        if ($sesCodes) {
            foreach ($sesCodes as $scode)
                $scode->delete();
        } //endif
        //return response
        return response('success', 200);
    }

    /**
     * Add table condition
     * @param Request $request
     */
    public function add_table_default($prodId)
    {
        $productID = $prodId;

        $table_value = env('TABLE_VALUE', 9.99);

        $additional_table = new CartCondition(array(
            'name' => 'Massage Table',
            'type' => 'addtable',
            'target' => 'item',
            'value' => $table_value,
            'order' => 2,
        ));

        //add table condition to the item cart
        \Cart::addItemCondition($productID, $additional_table);

        //get item and update attributes has table index
        $item = \Cart::get($productID);
        $attributes = $item->attributes;
        $attributes['has_table'] = true;
        $attributes['table_value'] = $table_value;
        \Cart::update($productID, array('attributes' => $attributes));

        //return response
        $message = [
            'success' => true,
            'message' => null,
            'data' => [
                'has_table' => $attributes['has_table'],
                'total' => $item->getPriceSumWithConditions()
            ],
        ];
        //return response
        return response($message, 200);
    }

    /**
     * Add table condition
     * @param Request $request
     */
    public function add_table(Request $request)
    {
        $productID = $request->cartId;
        $table_value = env('TABLE_VALUE', 9.99);

        //check again if table can be added to the basket
        $check = \Cart::get($productID);

        //cannnot order table if the area is not covered
        $postCode = Postcode::where('postcode', $check->attributes->postcode)->first();
        $district = $postCode->zone->district()->first();
        $deliverInArea = (bool) $district->table_restriction->display;

        if (!$deliverInArea) {
            return response([
                'success' => false,
                'message' => trans('schedules::booking.massage_table_not_deliverable'),
                'data' => [],
            ], 200);
        }

        //cannot order table only over 24h
        if (!$check->attributes->can_order_table) {
            return response([
                'success' => false,
                'message' => trans('schedules::booking.massage_table_24_notice'),
                'data' => [],
            ], 200);
        } //endif

        if ($check->attributes->has_table) {
            return response([
                'success' => false,
                'message' => 'Table has been already added!',
                'data' => [
                    'has_table' => true,
                    'total' => $check->getPriceSumWithConditions(),
                ],
            ], 200);
        }

        $additional_table = new CartCondition(array(
            'name' => 'Massage Table',
            'type' => 'addtable',
            'target' => 'item',
            'value' => $table_value,
            'order' => 2,
        ));

        //add table condition to the item cart
        \Cart::addItemCondition($productID, $additional_table);

        //get item and update attributes has table index
        $item = \Cart::get($productID);
        $attributes = $item->attributes;
        $attributes['has_table'] = true;
        $attributes['table_value'] = $table_value;
        \Cart::update($productID, array('attributes' => $attributes));

        //return response
        $message = [
            'success' => true,
            'message' => null,
            'data' => [
                'has_table' => $attributes['has_table'],
                'total' => $item->getPriceSumWithConditions()
            ],
        ];

        //return response
        return response($message, 200);
    }

    /**
     * Remove table condition
     * @param Request $request
     */
    public function remove_table(Request $request)
    {
        $productID = $request->cartId;

        //remove table condition from the item table
        \Cart::removeItemCondition($productID, $conditionName = "Massage Table");

        //get item
        $item = \Cart::get($productID);
        $attributes = $item->attributes;
        $attributes['has_table'] = false;
        $attributes['table_value'] = 0;
        \Cart::update($productID, array('attributes' => $attributes));


        //return response
        $message = [
            'success' => true,
            'data' => [
                'has_table' => $attributes['has_table'],
                'total' => $item->getPriceSumWithConditions(),
            ]
        ];

        //return response
        return response($message, 200);
    }

    /**
     * Add table condition
     * @param Request $request
     */
    public function add_voucher(Request $request)
    {

        $productID = $request->cartId;

        //get item cart
        $item = \Cart::get($productID);

        if (!$item) {
            return response([
                'success' => false,
                'message' => "Oops, something went wrong! Please try again.",
                'data' => \Cart::getContent(),
                'itemId' => $productID,
            ], 200);
        }


        $appliedCond = collect($item->conditions);

        //check if item has already voucher applied
        if ($item->attributes->has_voucher)
            return response([
                'success' => false,
                'message' => "You can add only one voucher or code!",
                'data' => [],
            ], 200);

        //get voucher code

        $checkVoucher = new VoucherRepository();

        $voucher = $checkVoucher->validate_voucher($request->value, $productID, $this->user);

        //if voucher is not valid, return response with message
        if (!$voucher['valid'])
            return response([
                'success' => false,
                'message' => $voucher['message'],
                'data' => [],
            ], 200);


        //compose condition amount/percent
        if ($voucher['voucher']->type == "value") {
            $condValue = - ($voucher['voucher']->value > $item->getPriceSum() ? $item->getPriceSum() : $voucher['voucher']->value);
        } else {
            //the value is as percentage
            $condValue = -$voucher['voucher']->value . "%";
        }

        //add voucher condition
        $additional_voucher = new CartCondition(array(
            'name' => 'Voucher',
            'type' => 'Voucher',
            'target' => 'item',
            'value' => $condValue,
            'order' => 0,
        ));

        //add table condition to the item cart
        \Cart::addItemCondition($productID, $additional_voucher);

        //get item and update attributes has table index
        $item = \Cart::get($productID);
        $attributes = $item->attributes;
        $attributes['has_voucher'] = true;
        $attributes['voucher'] = [
            'id' => $voucher['voucher']->id,
            'name' => $voucher['voucher']->name,
            'code' => $voucher['voucher']->code,
            'value' => $voucher['voucher']->value,
            'type' => $voucher['voucher']->type,
            'discount' => $condValue,
        ];

        \Cart::update($productID, array('attributes' => $attributes));

        //add voucher to session basket voucher
        $basketVoucher = [
            'basket_item_id' => $productID,
            'basket_item_value' => $item->getPriceSum(), // basket item value without conditions
            'session_id' => $request->session()->getId(),
            'voucher_code' => $voucher['voucher']->code,
        ];
        BasketVoucher::create($basketVoucher);

        //return response
        $message = [
            'success' => true,
            'data' => [
                'discount' => (-$condValue),
                'total' => $item->getPriceSumWithConditions(),
            ],
            'cart' => \Cart::getContent(),
            'session' => $request->session()->getId(),
        ];

        //return response
        return response($message, 200);
    }

    /**
     * Remove table condition
     * @param Request $request
     */
    public function remove_voucher(Request $request)
    {
        $productID = $request->cartId;

        //remove table condition from the item table
        \Cart::removeItemCondition($productID, $conditionName = "Voucher");

        //get item
        $item = \Cart::get($productID);
        $attributes = $item->attributes;
        $attributes['has_voucher'] = false;
        $attributes['voucher'] = [];

        //update cart attributes
        \Cart::update($productID, array('attributes' => $attributes));

        //remove from session basket
        $sesVoucher = BasketVoucher::where('basket_item_id', $productID)
            ->where('session_id', $request->session()->getId())
            ->first();
        if ($sesVoucher)
            $sesVoucher->delete();


        //create response message
        $message = [
            'success' => true,
            'data' => [
                'total' => $item->getPriceSumWithConditions(),
            ]
        ];

        //return response
        return response($message, 200);
    }

    /**
     * Pay method
     * @param Request $request
     */
    public function pay2(Request $request)
    {

        //card restriction
        return response([
            'success' => false,
            'message' => trans('schedules::payment.message_card_restriction'),
        ], 403);

        if (\Cart::isEmpty()) {
            return response([
                'success' => false,
                'message' => 'Time\'s up. The therapists reservations has overdue. Ooops, something goes wrong!',
            ], 200);
        } //endif

        $total = \Cart::getTotal();
        $user = $this->user;
        $token = $request->input('payment-method-nonce');

        //if user has no plans, create one
        if (!$user->braintree_id) {
            try {
                $user->newSubscription('single-charge', "qrjb")->create($token, [
                    'email' => $user->email,
                    'phone' => $user->profile->mobile_phone,
                ]);

                $name = "massage services";
                $response = $user->invoiceFor($name, $total);

                //register payment
                $this->register_payment($response, $request);
            } catch (\Exception $e) {
                $message = $e->getMessage();
                $message = str_ireplace('braintree', 'Zen London', $message);

                return response([
                    'success' => false,
                    'message' => $message,
                ], 200);
            } //end try/catch
        } else {
            //update token for each payment
            try {
                $user->updateCard($token);
                $name = "massage services";
                $response = $user->invoiceFor($name, $total);

                //register payment
                $this->register_payment($response, $request);

                return response([
                    'success' => true,
                    'message' => 'YOUR ORDER IS CONFIRMED',
                    'card_info' => [
                        'payment_id' => $user->braintree_id,
                        'paypal_email' => $user->paypal_email,
                        'card_brand' => $user->card_brand,
                        'card_last_four' => $user->card_last_four,
                        'expiry' => $response->transaction->creditCardDetails->expirationDate,
                    ],
                ], 200);
            } catch (\Exception $e) {
                $message = $e->getMessage();
                $message = str_ireplace('braintree', 'Zen London', $message);

                return response([
                    'success' => false,
                    'message' => $message,
                ], 200);
            }
        }

        //change user amount
        //register payment
        //        $this->register_payment($response,$request);
        //
        //        //redirect to success page
        //        $user = User::find($this->user->id);
        //        return response([
        //            'success'=>true,
        //            'message'=>'YOUR ORDER IS CONFIRMED',
        //            'card_info' => [
        //                'payment_id' => $user->braintree_id,
        //                'paypal_email' => $user->paypal_email,
        //                'card_brand' => $user->card_brand,
        //                'card_last_four' => $user->card_last_four,
        //                'expiry'=>$response->transaction->creditCardDetails->expirationDate,
        //            ],
        //        ],200);
    }

    // public function pay(Request $request) {
    //     if (\Cart::isEmpty()) {
    //         return response([
    //             'success' => false,
    //             'message' => 'Time\'s up. The therapists reservations has overdue.',
    //                 ], 200);
    //     } //endif

    //     if(!empty($request->paymentIntentId)) {

    //     }

    //     $paymentMethodId = $request->paymentMethodId;
    //     $amount = \Cart::getTotal(); // Replace with the desired amount in cents
    //     $currency = 'usd'; // Replace with the desired currency
    //     $stripeSecretKey = env('stripe_secret_key');
    //     $url = 'https://api.stripe.com/v1/payment_intents';

    //     $data = [
    //         'amount' => $amount,
    //         'currency' => $currency,
    //         'payment_method' => $paymentMethodId,
    //         'confirmation_method' => 'manual', // Set to 'manual' for preauthorization
    //         'capture_method' => 'manual', // Set to 'manual' for preauthorization
    //     ];

    //     $data = http_build_query($data);

    //     $ch = curl_init();
    //     curl_setopt($ch, CURLOPT_URL, $url);
    //     curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
    //     curl_setopt($ch, CURLOPT_POST, true);
    //     curl_setopt($ch, CURLOPT_POSTFIELDS, $data);
    //     curl_setopt($ch, CURLOPT_HTTPHEADER, [
    //         'Authorization: Bearer ' . $stripeSecretKey,
    //         'Content-Type: application/x-www-form-urlencoded',
    //     ]);

    //     try {
    //         $response = curl_exec($ch);

    //         if ($response === false) {
    //             throw new \Exception(curl_error($ch));
    //         }

    //         $responseData = json_decode($response, true);
    //         // dd($responseData);
    //         if (isset($responseData['error'])) {
    //             return response()->json(['error' => $responseData['error']['message']], 500);
    //         } else {
    //             $this->payment_pending($request, $responseData);
    //             //return success response
    //             return response([
    //                 'success' => true,
    //                 'message' => 'Your appointment has been successfully registered',
    //                     ], 200);
    //             // return redirect(route('bookings.basket.paysuccess'));
    //             // return response()->json(['client_secret' => $responseData['client_secret']]);
    //         }
    //     } catch (\Exception $e) {
    //         return response()->json(['error' => $e->getMessage()], 500);
    //     } finally {
    //         curl_close($ch);
    //     }
    // }

    public function pay(Request $request)
    {
        if (\Cart::isEmpty()) {
            return response([
                'success' => false,
                'message' => 'Time\'s up. The therapists reservations has overdue.',
            ], 200);
        } //endif

        if (!empty($request->paymentIntentId)) {
            $this->payment_pending($request);
            //return success response
            return response([
                'success' => true,
                'message' => 'Your appointment has been successfully registered',
            ], 200);
            // return redirect(route('bookings.basket.paysuccess'));
            // return response()->json(['client_secret' => $responseData['client_secret']]);
        } else {
            return response([
                'success' => false,
                'message' => 'Payment is not varified',
            ], 200);
        }
    }

    public function payment_pending($request)
    {
        if (\Cart::isEmpty()) {
            return response([
                'success' => false,
                'message' => 'Time\'s up. The therapists reservations has overdue.',
                'cart' => \Cart::getContent(),
            ], 403);
        } //endif


        //get current user
        $user = User::find($this->user->id);

        //get total amount
        $total = \Cart::getTotal();

        //register payment
        DB::beginTransaction();

        //Create order
        $dataOrder = [
            'user_id' => $this->user->id,
            'amount' => \Cart::getTotal(),
            'type' => 'cash',
        ];

        $order = Order::create($dataOrder);

        $voucherRepo = new VoucherRepository();

        //create booking orders
        $bookingOrders = [];
        foreach (\Cart::getContent() as $item) {
            $allInfo = $item->attributes;
            $allInfo['price_net'] = $item->getPriceSum();
            unset($allInfo['reserved_until']);
            //create order bookings array
            $data = [
                'order_id' => $order->id,
                'user_id' => $this->user->id,
                'is_active' => true,
                'amount' => $item->getPriceSumWithConditions(),
                'date' => Carbon::createFromFormat('d M Y', $item->attributes->date)->format('Y-m-d'),
                'hour' => $item->attributes->hour,
                'duration' => $item->attributes->duration,
                'duration_min' => $item->attributes->duration_min,
                'massage_type' => $item->attributes->massage_type,
                'address' => $item->attributes->address ? $item->attributes->address : 'no address',
                'location' => $item->attributes->location ? $item->attributes->location : 'location not found',
                'locationGeo' => json_encode($item->attributes->locationGeo),
                'orderInfo' => json_encode($allInfo),
                'updatedby_id' => $this->user->id,
            ];

            //save booking order
            $bookorder = BookingOrder::create($data);

            //attach therapists to booking order
            foreach ($allInfo['therapistIds'] as $thid) {
                $bookorder->therapists()->attach($thid, [
                    'date' => Carbon::createFromFormat('d M Y', $item->attributes->date)->format('Y-m-d'),
                    'duration' => $item->attributes->duration_min,
                    'hour' => $item->attributes->hour
                ]);
            } //endforeach
            //if voucher code was used, mark it as used
            if ($item->attributes->has_voucher) {
                $voucherRepo->mark_as_used($item->attributes->voucher['code'], $item->getPriceSum(), $item->id);
            } //end
            //start a new thread message
            $this->book->create_thread($bookorder);

            $bookingOrders[] = $bookorder;
        } //endforeach



        //add mobile notifications
        foreach ($bookingOrders as $bo) {
            $notif_message = trans("schedules::booking.mobile_new_order", ['number' => $bo->id, 'date' => $bo->date_to_human, 'hour' => $bo->hour_to_human]);

            $notif_users[] = $bo->user_id;
            $boInfo = json_decode($bo->orderInfo, true);
            $boTherapistsIds = $boInfo['therapistIds'];

            foreach ($boTherapistsIds as $thid)
                $notif_users[] = $thid;

            //store notifications

            foreach ($notif_users as $user)
                NotifRepository::add($user, $notif_message, 'booking', 'New Booking');
        } //endforeach


        //delete session tables: voucher and therapist
        $session_id = $request->session()->getId();

        if (!empty($session_id)) {

            $sesTh = BasketTherapist::where('session_id', $session_id)->get();


            if ($sesTh) {
                foreach ($sesTh as $sth) {
                    $sth->delete();
                }
            } //endif


            $sesCodes = BasketVoucher::where('session_id', $session_id)->get();


            if ($sesCodes) {
                foreach ($sesCodes as $scode) {
                    $scode->delete();
                }
            } //endif
        }


        //commit transaction order details
        if ($order) {
            $data = [
                'user_id' => Auth::user()->id,
                'payment_id' => $request->paymentIntentId,
                'order_id' => $order->id,
                'order_info' => json_encode($order)
            ];
            $payment = PendingPayment::create($data);
            if ($payment) {

                DB::commit();

                //clear cart contents
                \Cart::clear();

                //unset session booking key
                //$request->session()->forget('booking');

                Session::put('booking.selected_therapists', []);

                //send email
                $this->sendEmailCheckout($bookingOrders);
            } else {
                DB::rollBack();
            }
            //             DB::commit();
            // //            DB::commit();
            //             //clear cart contents
            //             \Cart::clear();

            //             //unset session booking key
            //             $request->session()->forget('booking');

            //             //send email
            //             $this->sendEmailCheckout($bookingOrders);
        } else {
            DB::rollBack();

            return response([
                'success' => false,
                'message' => 'Something went wrong. Please try again!',
            ], 403);
        }

        //return success response
        return response([
            'success' => true,
            'message' => 'Your appointment has been successfully registered',
        ], 200);
    }

    public function pay_from_admin(Request $request)
    {

        if (\Cart::isEmpty()) {
            return response([
                'success' => false,
                'message' => 'Time\'s up. The therapists reservations has overdue.',
            ], 200);
        } //endif

        $gateway = Omnipay::create('SagePay\Direct');
        $gateway->setVendor(env('SAGEPAY_VENDOR_NAME'));
        $gateway->setTestMode(env('SAGEPAY_TEST_MODE'));

        $total = \Cart::getTotal();
        $user = $this->user;
        $billingAddress = $user->address()->orderBy('is_main', 'desc')->first();

        $expiry = explode('/', $request->card_expiry);

        try {
            $card = new CreditCard([
                'firstName' => $user->profile->first_name,
                'lastName' => $user->profile->last_name,
                'number' => $request->card_number, //4462000000000003
                'expiryMonth' => $expiry[0], //6
                'expiryYear' => $expiry[1], //2030
                'cvv' => $request->card_cvv, //123
                //billing
                'billingAddress1' => $request->billing_address ?: env('SAGEPAY_BILLING_ADDR1'),
                'billingCity' => $request->billing_county ?: env('SAGEPAY_BILLING_CITY'),
                'billingPostcode' => $request->billing_postcode ?: env('SAGEPAY_BILLING_POSTCODE'),
                'billingCountry' => $request->billing_country ?: 'GB',
                'billingPhone' => $user->profile->mobile_number,
                //shipping
                'shippingAddress1' => $billingAddress ? $billingAddress->address : env('SAGEPAY_BILLING_ADDR1'),
                'shippingState' => $billingAddress ? $billingAddress->county : env('SAGEPAY_BILLING_CITY'),
                'shippingCity' => $billingAddress ? $billingAddress->county : env('SAGEPAY_BILLING_CITY'),
                'shippingPostcode' => $billingAddress ? $billingAddress->postcode : env('SAGEPAY_BILLING_POSTCODE'),
                'shippingCountry' => 'GB',
                'shippingPhone' => $user->profile->mobile_number,
            ]);
        } catch (\Exception $e) {
            $message = $e->getMessage();
            return response([
                'success' => false,
                'message' => $message,
                'error_code' => $e->getCode(),
            ], 200);
        }

        $transactionId = time();

        //add to the request
        $request->transaction_id = $transactionId;

        try {
            $response = $gateway->purchase(array(
                'amount' => $total,
                'currency' => env('SAGEPAY_CCY'),
                'card' => $card,
                'notifyUrl' => url('sagepay-process'),
                'redirectUrl' => url('sagepay-process'),
                'transactionId' => $transactionId,
                'description' => 'Massage Services',
                'billingCountry' => 'GB',
            ))->send();
        } catch (\Exception $e) {
            $message = $e->getMessage();
            return response([
                'success' => false,
                'message' => $message,
                'error_code' => $e->getCode(),
            ], 200);
        }

        if ($response->isSuccessful()) {

            //register payment
            $this->register_payment($response, $request);


            //redirect to success page
            return response([
                'success' => true,
                'message' => 'YOUR ORDER IS CONFIRMED',
            ], 200);
        } elseif ($response->isRedirect()) {
            return response([
                'success' => false,
                'message' => 'Redirect occured by the payment processor',
                'error_code' => '',
            ], 200);
        } else {
            return response([
                'success' => false,
                'message' => $response->getMessage(),
                'error_code' => $response->getCode(),
            ], 200);
        }
    }

    /**
     * Pay with existing card
     * @param Request $request
     * @return \Illuminate\Http\RedirectResponse|\Illuminate\Routing\Redirector
     */
    public function pay_with_existing_card(Request $request)
    {

        //card restriction
        return response([
            'success' => false,
            'message' => trans('schedules::payment.message_card_restriction'),
        ], 403);


        if (\Cart::isEmpty()) {

            $info = json_encode(\Cart::getContent());

            return response([
                'success' => false,
                'message' => 'Time\'s up. The therapists reservations has overdue.',
            ], 403);
        } //endif
        //get current user
        $user = $this->user;

        if (!$user->braintree_id) {
            return response([
                'success' => false,
                'message' => 'You have no valid card defined. Please enter one!',
            ], 200);
        } //end
        //        return response([
        //            'success'=>false,
        //            'message'=>'You have no valid card defined. Please enter one!',
        //        ],200);
        //get total amount
        $total = round(\Cart::getTotal(), 2);

        //charge user amount
        try {
            $name = "massage services";
            $response = $user->invoiceFor($name, $total);
        } catch (\Exception $e) {

            $message = $e->getMessage();
            $message = str_ireplace('braintree', 'Zen London', $message);

            return response([
                'success' => false,
                'message' => $message,
            ], 200);
        }

        //register payment
        $this->register_payment($response, $request);

        //redirect to success page
        return response([
            'success' => true,
            'message' => 'YOUR ORDER IS CONFIRMED',
        ], 200);
    }

    /**
     * Pay with existing card
     * @param Request $request
     * @return \Illuminate\Http\RedirectResponse|\Illuminate\Routing\Redirector
     */
    public function pay_with_cash(Request $request)
    {
        if (\Cart::isEmpty()) {
            return response([
                'success' => false,
                'message' => 'Time\'s up. The therapists reservations has overdue.',
                'cart' => \Cart::getContent(),
            ], 403);
        } //endif




        //get current user
        $user = User::find($this->user->id);


        //get total amount
        $total = \Cart::getTotal();

        //register payment
        DB::beginTransaction();

        //Create order
        $dataOrder = [
            'user_id' => $this->user->id,
            'amount' => \Cart::getTotal(),
            'type' => 'cash',
        ];

        $order = Order::create($dataOrder);

        $voucherRepo = new VoucherRepository();




        //create booking orders
        $bookingOrders = [];
        foreach (\Cart::getContent() as $item) {
            $allInfo = $item->attributes;
            $allInfo['price_net'] = $item->getPriceSum();
            unset($allInfo['reserved_until']);
            //create order bookings array
            $data = [
                'order_id' => $order->id,
                'user_id' => $this->user->id,
                'is_active' => true,
                'amount' => $item->getPriceSumWithConditions(),
                'date' => Carbon::createFromFormat('d M Y', $item->attributes->date)->format('Y-m-d'),
                'hour' => $item->attributes->hour,
                'duration' => $item->attributes->duration,
                'duration_min' => $item->attributes->duration_min,
                'massage_type' => $item->attributes->massage_type,
                'address' => $item->attributes->address ? $item->attributes->address : 'no address',
                'location' => $item->attributes->location ? $item->attributes->location : 'location not found',
                'locationGeo' => json_encode($item->attributes->locationGeo),
                'orderInfo' => json_encode($allInfo),
                'updatedby_id' => $this->user->id,
            ];

            //save booking order
            $bookorder = BookingOrder::create($data);

            //attach therapists to booking order
            foreach ($allInfo['therapistIds'] as $thid) {
                $bookorder->therapists()->attach($thid, [
                    'date' => Carbon::createFromFormat('d M Y', $item->attributes->date)->format('Y-m-d'),
                    'duration' => $item->attributes->duration_min,
                    'hour' => $item->attributes->hour
                ]);
            } //endforeach
            //if voucher code was used, mark it as used
            if ($item->attributes->has_voucher) {
                $voucherRepo->mark_as_used($item->attributes->voucher['code'], $item->getPriceSum(), $item->id);
            } //end
            //start a new thread message
            $this->book->create_thread($bookorder);

            $bookingOrders[] = $bookorder;
        } //endforeach



        //add mobile notifications
        foreach ($bookingOrders as $bo) {
            $notif_message = trans("schedules::booking.mobile_new_order", ['number' => $bo->id, 'date' => $bo->date_to_human, 'hour' => $bo->hour_to_human]);

            $notif_users[] = $bo->user_id;
            $boInfo = json_decode($bo->orderInfo, true);
            $boTherapistsIds = $boInfo['therapistIds'];

            foreach ($boTherapistsIds as $thid)
                $notif_users[] = $thid;

            //store notifications

            foreach ($notif_users as $user)
                NotifRepository::add($user, $notif_message, 'booking', 'New Booking');
        } //endforeach


        //delete session tables: voucher and therapist
        $session_id = $request->session()->getId();

        if (!empty($session_id)) {

            $sesTh = BasketTherapist::where('session_id', $session_id)->get();


            if ($sesTh) {
                foreach ($sesTh as $sth) {
                    $sth->delete();
                }
            } //endif


            $sesCodes = BasketVoucher::where('session_id', $session_id)->get();


            if ($sesCodes) {
                foreach ($sesCodes as $scode) {
                    $scode->delete();
                }
            } //endif
        }


        //commit transaction order details
        if ($order) {
            DB::commit();
            //            DB::commit();
            //clear cart contents
            \Cart::clear();

            //unset session booking key
            $request->session()->forget('booking');

            //send email
            $this->sendEmailCheckout($bookingOrders);
        } else {
            DB::rollBack();

            return response([
                'success' => false,
                'message' => 'Something went wrong. Please try again!',
            ], 403);
        }

        //return success response
        return response([
            'success' => true,
            'message' => 'Your appointment has been successfully registered',
        ], 200);
    }

    /**
     * Register payment
     * @param $response
     */
    protected function register_payment($response, Request $request)
    {

        $messageArr = explode(':', $response->getMessage());
        $message = trim($messageArr[1]);

        DB::beginTransaction();

        //card details
        $maskedNumber = substr($request->card_number, 0, 4) . ' **** **** ' . substr($request->card_number, -4);
        $lastFour = substr($request->card_number, -4);

        //attach transaction refference to the user
        $user = $this->user;
        $user->card_reference = $response->getTransactionReference();
        $user->card_last_four = $lastFour;
        $user->save();

        //Create order
        $dataOrder = [
            'user_id' => $this->user->id,
            'amount' => \Cart::getTotal(),
            'type' => 'card',
            'card_trans_id' => $response->getTransactionReference(),
            'card_trans_status' => (bool) $response->isSuccessful(),
            'card_details' => json_encode([
                'customerLocation' => '',
                'cardType' => '',
                'expirationDate' => $request->expiry_month . '/' . $request->expiry_year,
                'imageUrl' => '',
                'maskedNumber' => $maskedNumber,
                'last4' => $lastFour,
                'bin' => '',
                'transaction_id' => $request->transaction_id,
                'transaction_reference' => $response->getTransactionReference(),
                'security_id' => $response->getSecurityKey(),
            ]),
        ];

        $order = Order::create($dataOrder);

        $voucherRepo = new VoucherRepository();

        //create booking orders
        $bookingOrders = [];
        foreach (\Cart::getContent() as $item) {
            $allInfo = $item->attributes;
            $allInfo['price_net'] = $item->getPriceSum();
            $allInfo['amount'] = $item->getPriceSumWithConditions();
            unset($allInfo['reserved_until']);

            //create order bookings array
            $data = [
                'order_id' => $order->id,
                'user_id' => $this->user->id,
                'is_active' => true,
                'amount' => $item->getPriceSumWithConditions(),
                'date' => Carbon::createFromFormat('d M Y', $item->attributes->date)->format('Y-m-d'),
                'hour' => $item->attributes->hour,
                'duration' => $item->attributes->duration,
                'duration_min' => $item->attributes->duration_min,
                'massage_type' => $item->attributes->massage_type,
                'massage_type_id' => $item->attributes->massage_type_id,
                'address' => $item->attributes->address,
                'location' => $item->attributes->location,
                'locationGeo' => json_encode($item->attributes->locationGeo),
                'orderInfo' => json_encode($allInfo),
                'card_trans_id' => $response->getTransactionReference(),
                'card_trans_status' => (bool) $response->isSuccessful(),
                'card_details' => json_encode([
                    'customerLocation' => '',
                    'cardType' => '',
                    'expirationDate' => @$request->expiry,
                    'imageUrl' => '',
                    'maskedNumber' => @$maskedNumber,
                    'last4' => @$lastFour,
                    'bin' => '',
                    'transaction_id' => @$request->transaction_id,
                    'transaction_reference' => @$response->getTransactionReference(),
                    'security_id' => @$response->getSecurityKey(),
                ]),
                'updatedby_id' => $this->user->id,
            ];

            //save booking order
            $bookorder = BookingOrder::create($data);

            //create invoice
            if ($response->getTransactionReference()) {
                $invRepo = new BookingInvoiceRepository();
                $invRepo->new_invoice($bookorder);
            } //endif
            //attach therapists to booking order
            foreach ($allInfo['therapistIds'] as $thid) {
                $bookorder->therapists()->attach($thid, [
                    'date' => Carbon::createFromFormat('d M Y', $item->attributes->date)->format('Y-m-d'),
                    'duration' => $item->attributes->duration_min,
                    'hour' => $item->attributes->hour
                ]);
            } //endforeach
            //if voucher code was used, mark it as used
            if ($item->attributes->has_voucher) {
                $voucherRepo->mark_as_used($item->attributes->voucher['code'], $item->getPriceSum(), $item->id);
            } //end
            //start a new thread message
            $this->book->create_thread($bookorder);

            $bookingOrders[] = $bookorder;
        } //endforeach



        //delete session tables: voucher and therapist
        $session_id = $request->session()->getId();

        $sesTh = BasketTherapist::where('session_id', $session_id)->get();
        if ($sesTh) {
            foreach ($sesTh as $sth)
                $sth->delete();
        } //endif

        $sesCodes = BasketVoucher::where('session_id', $session_id)->get();
        if ($sesCodes) {
            foreach ($sesCodes as $scode)
                $scode->delete();
        } //endif
        //start a new thread message
        $this->book->create_thread($bookorder);

        //commit transaction order details
        if ($order) {
            DB::commit();

            //clear cart contents
            \Cart::clear();

            //unset session booking key
            $request->session()->forget('booking');

            //send email
            // $this->sendEmailCheckout($bookingOrders);

            return true;
        } else {
            DB::rollBack();
            return false;
        }
    }

    /**
     * Send condfirmation order
     * @param $order
     */
    public function sendEmailCheckout($orders)
    {
        $user = User::findOrFail($orders[0]->user_id);
        $data['user'] = $user;
        $data['orders'] = $orders;

        //send confirmation email
        Mail::send('schedules::frontend.emails.neworder', ['user' => $user, 'orders' => $orders], function ($m) use ($data) {
            $m->from(env('MAIL_FROM'), env('APP_NAME'));
            $m->to($data['user']->email, $data['user']->name);
            $m->bcc(explode(',', env('MAIL_NEWORDER_BCC')), env('MAIL_NEWORDER_BCC_NAME'));
            $m->subject(env('APP_NAME') . ' – booking confirmation');
        });

        //send email to therapists
        $order = $orders[0];
        $boInfo = json_decode($order->orderInfo, true);
        $boTherapistsIds = $boInfo['therapistIds'];
        $therapists = User::whereIn('id', $boTherapistsIds)->get();
        $dataTh['user'] = $therapists;
        $dataTh['orders'] = $orders;

        foreach ($therapists as $therapist) {
            $dataTh['user'] = $therapist;
            Mail::send('schedules::frontend.emails.therapist_neworder', ['user' => $therapist, 'orders' => $orders], function ($m) use ($dataTh) {
                $m->from(env('MAIL_FROM'), env('APP_NAME'));
                $m->to($dataTh['user']->email, $dataTh['user']->name);
                $m->bcc(explode(',', env('MAIL_NEWORDER_BCC')), env('MAIL_NEWORDER_BCC_NAME'));
                $m->subject(env('APP_NAME') . ' – you have a new booking');
            });
        } //end foreach
    }

    /**
     * Get a client payment token
     */
    public function get_client_payment_token()
    {
        $token = null;
        try {
            $token = ClientToken::generate();
            return response([
                'success' => true,
                'token' => $token,
            ], 200);
        } catch (Exception $error) {
            response([
                'success' => false,
                'message' => $error->getMessage(),
                'token' => null,
            ], 200);
        } //end try catch
    }


    // Treatment Api
    public function inPerson()
    {
        $param = request('search');
        // dd($param);
        if ($param) {
            $this->data['search'] = $param;
            $this->data['services'] = ServiceType::whereIn('service_type_id', [1])->where('parent_category_id', 0)->where('name', 'LIKE', '%' . $param . '%')->orderBy('order_no')->get();
        } else {
            $this->data['services'] = ServiceType::whereIn('service_type_id', [1])->where('parent_category_id', 0)->orderBy('order_no')->get();
        }
        return response([
            'success' => true,
            'data' => $this->data,
        ], 200);
    }

    public function online()
    {
        $data = ServiceType::whereIn('service_type_id', [2])->where('parent_category_id', 0)->get();
        return response([
            'success' => true,
            'data' => $data,
        ], 200);
    }

    public function salonTreatments()
    {
        $param = request('search');
        if ($param) {
            $this->data['search'] = $param;
            $this->data['services'] = SalonCategory::where('image', '!=', NULL)
                ->where('image', '!=', '')
                ->where('is_showed', 1)
                ->where(function ($query) use ($param) {
                    $query->where('name', 'LIKE', '%' . $param . '%')
                        ->orWhere('search_keywords', 'LIKE', '%' . $param . '%');
                })
                ->get();
        } else {
            $this->data['services'] = SalonCategory::where('image', '!=', NULL)->where('image', '!=', '')->where('is_showed', 1)->get();
        }
        return response([
            'success' => true,
            'data' => $this->data,
        ], 200);
    }

    public function subCategory($id)
    {
        $this->data['parent_category'] = ServiceType::whereIn('id', [$id])->get();

        $this->data['services'] = ServiceType::whereIn('parent_category_id', [$id])->get();
        $category = ServiceType::whereIn('parent_category_id', [$id])->get();
        // $this->data['trID'] = $id;
        if (count($category) == 0) {
            $treatment_detail = ServiceType::whereIn('id', [$id])->get();
            return response([
                'success' => true,
                'data' => $treatment_detail,
            ], 200);
            //  return redirect()->back()->with('treatment_detail', $treatment_detail);
        } else {
            return response([
                'success' => true,
                'data' => $this->data,
            ], 200);
        }
    }

    public function treatmentInfo($id)
    {
        $treatment_info = ServiceType::whereIn('id', [$id])->get();
        return response([
            'success' => true,
            'data' => $treatment_info,
        ], 200);
    }

    public function deletecart($id)
    {
        // dd($id);
        BasketTherapist::where('basket_item_id', $id)->delete();
        //clear cart contents
        \Cart::remove($id);

        return response([
            'success' => true,
            'cart' => \Cart::getContent(),
        ], 200);
    }

    public function removecart()
    {
        //clear cart contents
        \Cart::clear();

        return response([
            'success' => true,
            'cart' => \Cart::getContent(),
        ], 200);
    }

    public function updatecartitem(Request $request)
    {
        // dd("here");
        //get input request
        $i = $request->all();

        //all fields must be set
        if (!$i['name'] || !$i['itemId'])
            return response(['message' => "not allowed"], 403);

        //allow only fields
        $allowed_names = ['user_name', 'user_phone', 'address', 'notes', 'county'];
        if (!in_array($i['name'], $allowed_names))
            return response(['message' => "not allowed"], 403);

        //get item cart and update value
        $item = \Cart::get($i['itemId']);
        $attributes = $item->attributes;
        $attributes[$i['name']] = $i['value'];
        \Cart::update($i['itemId'], array('attributes' => $attributes));

        //return success
        return response(['success' => true], 200);
    }

    // public function createPaymentIntent(Request $request)
    // {
    //     if (\Cart::isEmpty()) {
    //         return response([
    //             'success' => false,
    //             'message' => 'Time\'s up. The therapists reservations has overdue.',
    //         ], 200);
    //     } //endif

    //     if (empty($request->paymentMethodId)) {
    //         return response(['success' => false, 'message' => "Can't create intent. Please try again."], 200);
    //     }

    //     $paymentMethodId = $request->paymentMethodId;
    //     $amount = \Cart::getTotal() * 100; // Replace with the desired amount in cents
    //     // $amount = 100; // Replace with the desired amount in cents
    //     $currency = 'gbp'; // Replace with the desired currency
    //     $stripeSecretKey = env('stripe_secret_key');
    //     $url = 'https://api.stripe.com/v1/payment_intents';

    //     $data = [
    //         'amount' => $amount,
    //         'currency' => $currency,
    //         'payment_method' => $paymentMethodId,
    //         'confirmation_method' => 'automatic', // Set to 'manual' for preauthorization
    //         'capture_method' => 'manual', // Set to 'manual' for preauthorization
    //         // 'confirm' => false, // Manual confirmation
    //         'payment_method_types' => ['card'], // Allow card payments
    //     ];

    //     $data = http_build_query($data);

    //     $ch = curl_init();
    //     curl_setopt($ch, CURLOPT_URL, $url);
    //     curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
    //     curl_setopt($ch, CURLOPT_POST, true);
    //     curl_setopt($ch, CURLOPT_POSTFIELDS, $data);
    //     curl_setopt($ch, CURLOPT_HTTPHEADER, [
    //         'Authorization: Bearer ' . $stripeSecretKey,
    //         'Content-Type: application/x-www-form-urlencoded',
    //     ]);

    //     try {
    //         $response = curl_exec($ch);

    //         if ($response === false) {
    //             throw new \Exception(curl_error($ch));
    //         }

    //         $responseData = json_decode($response, true);
    //         // dd($responseData);
    //         if (isset($responseData['error'])) {
    //             return response()->json(['error' => $responseData['error']['message']], 500);
    //         } else {
    //             // return response()->json(['client_secret' => $responseData['client_secret']]);
    //             // redirect to temp page for handling the card action for 3d secure
    //             // return redirect(route('bookings.basket.paysuccess'));
    //             return response()->json([
    //                 'client_secret' => $responseData['client_secret'],
    //                 'payment_id' => $responseData['id']
    //             ]);
    //         }
    //     } catch (\Exception $e) {
    //         return response()->json(['error' => $e->getMessage()], 500);
    //     } finally {
    //         curl_close($ch);
    //     }
    // }

    public function createPaymentIntent(Request $request)
    {
        if (\Cart::isEmpty()) {
            return response([
                'success' => false,
                'message' => 'Time\'s up. The therapists reservations has overdue.',
            ], 200);
        } //endif

        $cartData = \Cart::getContent()->first();

        $totalAmount = \Cart::getTotal();
        $commisions = $cartData->attributes->duration_commision;

        $companyCommissionPercentage = $commisions['company_commision_percent'];
        $platformFee = ($totalAmount * $companyCommissionPercentage) / 100; // Platform fee in currency
        $serviceProviderId = $cartData->attributes->therapistIds[0];
        $serviceProvider = User::find($serviceProviderId);

        $proceedWithPayout = false;
        $stripeAccountId = null;
        if ($serviceProvider->stripe_connected == 1) {
            $stripeAccountId = $serviceProvider->stripe_account_id;
            $proceedWithPayout = true;
        }

        if (empty($request->paymentMethodId)) {
            return response(['success' => false, 'message' => "Can't create intent. Please try again."], 200);
        }

        $paymentMethodId = $request->paymentMethodId;
        $amount = $totalAmount * 100; // Replace with the desired amount in cents
        // $amount = 100; // Replace with the desired amount in cents
        $currency = 'gbp'; // Replace with the desired currency
        $stripeSecretKey = env('stripe_secret_key');
        $url = 'https://api.stripe.com/v1/payment_intents';

        // $data = [
        //     'amount' => $amount,
        //     'currency' => $currency,
        //     'payment_method' => $paymentMethodId,
        //     'confirmation_method' => 'automatic', // Set to 'manual' for preauthorization
        //     'capture_method' => 'manual', // Set to 'manual' for preauthorization
        //     // 'confirm' => false, // Manual confirmation
        //     'payment_method_types' => ['card'], // Allow card payments
        // ];

        $data = [
            'amount' => $amount,
            'currency' => $currency,
            'payment_method' => $paymentMethodId,
            'confirmation_method' => 'automatic', // Set to 'manual' for preauthorization
            'payment_method_types' => ['card'], // Allow card payments
            
            'payment_method_options' => [
                'card' => [
                    'request_three_d_secure' => 'challenge',
                ],
            ],
        ];

        // If therapist has Stripe account → marketplace payout
        if ($proceedWithPayout && !empty($stripeAccountId)) {

            $data['application_fee_amount'] = (int) round($platformFee * 100); // Platform fee in cents

            $data['transfer_data'] = [
                'destination' => $stripeAccountId
            ];
        }

        $data = http_build_query($data);

        $ch = curl_init();
        curl_setopt($ch, CURLOPT_URL, $url);
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
        curl_setopt($ch, CURLOPT_POST, true);
        curl_setopt($ch, CURLOPT_POSTFIELDS, $data);
        curl_setopt($ch, CURLOPT_HTTPHEADER, [
            'Authorization: Bearer ' . $stripeSecretKey,
            'Content-Type: application/x-www-form-urlencoded',
        ]);

        try {
            $response = curl_exec($ch);

            if ($response === false) {
                throw new \Exception(curl_error($ch));
            }

            $responseData = json_decode($response, true);
            // dd($responseData);
            if (isset($responseData['error'])) {
                return response()->json(['error' => $responseData['error']['message']], 500);
            } else {
                // return response()->json(['client_secret' => $responseData['client_secret']]);
                // redirect to temp page for handling the card action for 3d secure
                // return redirect(route('bookings.basket.paysuccess'));
                return response()->json([
                    'client_secret' => $responseData['client_secret'],
                    'payment_id' => $responseData['id']
                ]);
            }
        } catch (\Exception $e) {
            return response()->json(['error' => $e->getMessage()], 500);
        } finally {
            curl_close($ch);
        }
    }

    public function createPaymentIntentWithPayout(Request $request)
    {
        if (\Cart::isEmpty()) {
            return response([
                'success' => false,
                'message' => 'Time\'s up. The therapists reservations has overdue.',
            ], 200);
        } //endif

        $cartData = \Cart::getContent()->first();

        $totalAmount = \Cart::getTotal();
        $commisions = $cartData->attributes->duration_commision;

        $companyCommissionPercentage = $commisions['company_commision_percent'];
        $platformFee = ($totalAmount * $companyCommissionPercentage) / 100; // Platform fee in currency
        $serviceProviderId = $cartData->attributes->therapistIds[0];
        $serviceProvider = User::find($serviceProviderId);

        $proceedWithPayout = false;
        $stripeAccountId = null;
        if ($serviceProvider->stripe_connected == 1) {
            $stripeAccountId = $serviceProvider->stripe_account_id;
            $proceedWithPayout = true;
        }

        if (empty($request->paymentMethodId)) {
            return response(['success' => false, 'message' => "Can't create intent. Please try again."], 200);
        }

        $paymentMethodId = $request->paymentMethodId;
        $amount = $totalAmount * 100; // Replace with the desired amount in cents
        // $amount = 100; // Replace with the desired amount in cents
        $currency = 'gbp'; // Replace with the desired currency
        $stripeSecretKey = env('stripe_secret_key');
        $url = 'https://api.stripe.com/v1/payment_intents';

        // $data = [
        //     'amount' => $amount,
        //     'currency' => $currency,
        //     'payment_method' => $paymentMethodId,
        //     'confirmation_method' => 'automatic', // Set to 'manual' for preauthorization
        //     'capture_method' => 'manual', // Set to 'manual' for preauthorization
        //     // 'confirm' => false, // Manual confirmation
        //     'payment_method_types' => ['card'], // Allow card payments
        // ];

        $data = [
            'amount' => $amount,
            'currency' => $currency,
            'payment_method' => $paymentMethodId,
            'confirmation_method' => 'automatic', // Set to 'manual' for preauthorization
            'payment_method_types' => ['card'], // Allow card payments
            
            'payment_method_options' => [
                'card' => [
                    'request_three_d_secure' => 'challenge',
                ],
            ],
        ];

        // If therapist has Stripe account → marketplace payout
        if ($proceedWithPayout && !empty($stripeAccountId)) {

            $data['application_fee_amount'] = (int) round($platformFee * 100); // Platform fee in cents

            $data['transfer_data'] = [
                'destination' => $stripeAccountId
            ];
        }

        $data = http_build_query($data);

        $ch = curl_init();
        curl_setopt($ch, CURLOPT_URL, $url);
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
        curl_setopt($ch, CURLOPT_POST, true);
        curl_setopt($ch, CURLOPT_POSTFIELDS, $data);
        curl_setopt($ch, CURLOPT_HTTPHEADER, [
            'Authorization: Bearer ' . $stripeSecretKey,
            'Content-Type: application/x-www-form-urlencoded',
        ]);

        try {
            $response = curl_exec($ch);

            if ($response === false) {
                throw new \Exception(curl_error($ch));
            }

            $responseData = json_decode($response, true);
            // dd($responseData);
            if (isset($responseData['error'])) {
                return response()->json(['error' => $responseData['error']['message']], 500);
            } else {
                // return response()->json(['client_secret' => $responseData['client_secret']]);
                // redirect to temp page for handling the card action for 3d secure
                // return redirect(route('bookings.basket.paysuccess'));
                return response()->json([
                    'client_secret' => $responseData['client_secret'],
                    'payment_id' => $responseData['id']
                ]);
            }
        } catch (\Exception $e) {
            return response()->json(['error' => $e->getMessage()], 500);
        } finally {
            curl_close($ch);
        }
    }
}

ZeroDay Forums Mini