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/ |
<?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);
}
}
}