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/test.tradze.com/app/Modules/Schedules/Repositories/ |
<?php
namespace App\Modules\Schedules\Repositories;
use App\Modules\Invoices\Repositories\BookingInvoiceRepository;
use App\Modules\Schedules\Models\BookingOrder;
use App\Modules\Schedules\Models\Schedule;
use App\Modules\Postcodes\Models\Postcode;
use App\Modules\Services\Models\ServiceDuration;
use App\Modules\Services\Models\ServiceType;
use App\Modules\Users\Repositories\MessageThreadRepository;
use App\Modules\Vouchers\Models\Voucher;
use App\Modules\Vouchers\Repositories\VoucherRepository;
use App\User;
use App\Modules\Services\Models\FocalPoint;
use App\Modules\Schedules\Models\ScheduleDaysOff;
use Bican\Roles\Models\Role;
use Braintree\Transaction;
use Carbon\Carbon;
use Cmgmyr\Messenger\Models\Message;
use Cmgmyr\Messenger\Models\Participant;
use Cmgmyr\Messenger\Models\Thread;
use GoogleMaps\GoogleMaps;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Mail;
use Illuminate\Support\Facades\Session;
use Mockery\CountValidator\Exception;
use App\Modules\Notifications\Facades\NotifRepository;
use Omnipay\Omnipay;
class BookingClass
{
var $defaultServiceDuration = null;
public function __construct()
{
$this->defaultServiceDuration = ServiceDuration::where('is_default',1)->first();
}
/**
* Get available therapists
* @return array
*/
public function therapists()
{
$booking = Session::get('booking');
//dd($booking);
$users = collect();
//if one of mandatory fields is missing, return empty array results
$mandatory_fields = ['postcode', 'duration', 'massage', 'date'];
foreach ($mandatory_fields as $field) {
if (!isset($booking[$field]))
return $users;
} //endforeach
//get postcode zone
$postcode = Postcode::where('postcode', $booking['postcode'])->first();
//users are not available for the past dates
$today = Carbon::today();
$dateC = Carbon::createFromFormat('Y-m-d', $booking['date']);
$diff = $today->diffInHours($dateC, false);
if ($diff < 0)
return $users;
//query therapists
DB::enableQueryLog();
$users = User::OfTherapists()
->whereHas('servicetypes', function ($query) use ($booking) {
if (isset($booking['massage']) && $booking['massage'] > 0)
$query->where('users_servicetype.servicetype_id', $booking['massage']);
return $query;
})
->whereHas('zones', function ($query) use ($postcode) {
$query->where('users_area_coverage.zone_id', $postcode->zone_id);
return $query;
})
->whereHas('workingdays', function ($query) use ($booking) {
$weekday = date('w', strtotime($booking['date']));
$hour = $booking['hour'].':00';
$duration = ServiceDuration::find($booking['duration'])->duration;
$hourEnd = Carbon::createFromFormat('H:i:s',$hour)->addMinutes($duration)->format('H:i:s');
if (strtotime($hour)>strtotime($hourEnd))
return $query->where('id','-1');
$query->where('dayoff', 0);
$query->where('weekday', $weekday);
$query->whereRaw("TIME(STR_TO_DATE(bo_start, '%H:%i')) <= TIME(STR_TO_DATE('{$hour}','%H:%i')) and TIME(STR_TO_DATE(bo_end, '%H:%i')) >= TIME(STR_TO_DATE('{$hourEnd}','%H:%i'))");
return $query;
})
// ->whereDoesntHave('daysoff', function ($query) use ($booking) {
// if (!isset($booking['hour']))
// return $query;
//
// $dateHour = $booking['date'].' '.$booking['hour'].':00';
// $query->whereRaw("STR_TO_DATE('{$dateHour}','%Y-%m-%d %H:%i') between date_start and date_end");
// return $query;
// })
->whereDoesntHave('daysoff', function ($query) use ($booking) {
if (!isset($booking['hour']))
return $query;
$duration = ServiceDuration::find($booking['duration'])->duration;
$duration = $duration-1;
$dateHour = $booking['date'].' '.$booking['hour'].':00';
$dateHourEnd = $booking['date'].' '.date('H:i',strtotime($booking['hour']."+{$duration} minutes")).':00';
$query->whereRaw('STR_TO_DATE("'.$dateHour.'","%Y-%m-%d %H:%i") > date_start and date_end > STR_TO_DATE("'.$dateHour.'","%Y-%m-%d %H:%i")')
->orWhereRaw('STR_TO_DATE("'.$dateHourEnd.'","%Y-%m-%d %H:%i") > date_start and date_end > STR_TO_DATE("'.$dateHourEnd.'","%Y-%m-%d %H:%i")');
//dd($dateHour,$dateHourEnd);
return $query;
})
->orderBy('nr_crt')
->get();
//dd($users);
//unselect unavailable selected users
if (isset($booking['selected_therapists'])){
$usersAvailable=[];
foreach($users as $usr)
$usersAvailable[] = $usr->id;
foreach($booking['selected_therapists'] as $key=>$selected){
if (!in_array($selected,$usersAvailable))
unset($booking['selected_therapists'][$key]);
}
Session::put('booking',$booking);
}
if (isset($booking['hour']) && isset($booking['duration'])){
$duration = ServiceDuration::find($booking['duration']);
$bufferMin = 55;
$buffer = $duration->duration+55;
foreach($users as $key=>$u){
//remove user is he has already a booking at selected date&hour + duration interval
$count = $u->therapistbookings()
->where('date',$booking['date'])
->where(function($query) use ($booking, $duration, $buffer, $bufferMin){
return $query->whereRaw('
TIME("'.$booking['hour'].'") BETWEEN SUBTIME(`hour`,STR_TO_DATE(CONCAT(FLOOR('.$buffer.'/60),\':\',MOD('.$buffer.',60)),"%h:%i:%s")) AND ADDTIME(`hour`,STR_TO_DATE(CONCAT(FLOOR((duration+'.$bufferMin.')/60),\':\',MOD((duration+'.$bufferMin.'),60)),"%h:%i:%s"))
');
})
->whereHas('booking',function($query){
return $query->where('is_active',1);
})
->count();
if ($count) $users->forget($key);
$countSession = $u->sessionBlockedTherapists()
->where('date',$booking['date'])
->where(function($query) use ($booking, $duration, $buffer, $bufferMin){
return $query->whereRaw('
`hour` between SUBTIME("'.$booking['hour'].'",STR_TO_DATE(CONCAT(FLOOR('.$buffer.'/60),\':\',MOD('.$buffer.',60)),"%h:%i:%s")) and ADDTIME(ADDTIME("'.$booking['hour'].'",STR_TO_DATE(CONCAT(FLOOR('.$buffer.'/60),\':\',MOD('.$buffer.',60)),"%h:%i:%s")),"0:00:00")
OR
ADDTIME(`hour`, STR_TO_DATE(CONCAT(FLOOR(duration_min/60),\':\',MOD(duration_min,60)),"%h:%i:%s")) BETWEEN SUBTIME("'.$booking['hour'].'", "00:55:00") AND ADDTIME(ADDTIME("'.$booking['hour'].'",STR_TO_DATE(CONCAT(FLOOR('.$buffer.'/60),\':\',MOD('.$buffer.',60)),"%h:%i:%s")),"0:00:00")
');
})
->count();
if ($countSession) $users->forget($key);
} //end foreach
} //endif
$usersAvailable=[];
//unselect unavailable selected users
//if (isset($booking['selected_therapists'])){
foreach($users as $usr)
$usersAvailable[] = $usr->id;
if(isset($booking['selected_therapists']))
{
foreach($booking['selected_therapists'] as $key=>$selected){
if (!in_array($selected,$usersAvailable))
unset($booking['selected_therapists'][$key]);
}
}
Session::put('booking',$booking);
//}
//dd($usersAvailable);
$usersUnAvailable = User::OfTherapists()
->whereNotIn('id',$usersAvailable)
->whereHas('servicetypes', function ($query) use ($booking) {
if (isset($booking['massage']) && $booking['massage'] > 0)
$query->where('users_servicetype.servicetype_id', $booking['massage']);
return $query;
})
->whereHas('zones', function ($query) use ($postcode) {
$query->where('users_area_coverage.zone_id', $postcode->zone_id);
return $query;
})
->orderBy('nr_crt')
->get();
if($users)
{
$allUsers['available'] = $users;
}
if($usersUnAvailable)
{
$allUsers['unavailable'] = $usersUnAvailable;
}
//return results
return $allUsers;
}
/**
* Get available therapists right now based on their location and google time travel estimation
* @return array
*/
public function therapistsNow()
{
$users = collect();
$booking = Session::get('booking');
$booking['date'] = Carbon::today()->format('Y-m-d');
$booking['hour'] = Carbon::today()->format('H:i');
//check if the current date is marked as day off
$daysOff = $this->days_off($booking['date']);
if ($daysOff->count())
return $users;
//get weekday working hours: if weekday is non working day, return
$weekday = date('w',strtotime($booking['date']));
$whours = Schedule::where('weekday',$weekday)->where('open',1)->first();
if (!$whours)
return $users;
//the therapists can be booked only in working hours of the weekday
if (strtotime($whours->bo_end) < strtotime(date('H:i')))
return $users;
//if the start working day hour is bigger then the current hour, return no therapists
if (strtotime($whours->bo_start) > strtotime(date('H:i')))
return $users;
//if the current hour + desired massage duration exceed closing time, return no therapists
if (isset($booking['duration'])){
$checkduration = ServiceDuration::find($booking['duration'])->duration;
if (strtotime($whours->bo_end) < strtotime(date('H:i')."+{$checkduration} minutes"))
return $users;
}
//if one of mandatory fields is missing, return empty array results
$mandatory_fields = ['duration','massage','date'];
foreach($mandatory_fields as $field){
if (!isset($booking[$field]))
return $users;
} //endforeach
//get postcode zone
// $postcode = Postcode::where('postcode',$booking['postcode'])->first();
//users are not available for the past dates
$today = Carbon::today();
$dateC = Carbon::createFromFormat('Y-m-d',$booking['date']);
$diff = $today->diffInHours($dateC,false);
if ($diff<0)
return $users;
//query therapists
// DB::enableQueryLog();
$users = User::OfTherapists()
->whereHas('servicetypes', function ($query) use ($booking) {
if (isset($booking['massage']) && $booking['massage']>0)
$query->where('users_servicetype.servicetype_id', $booking['massage']);
return $query;
})
->whereHas('zones', function ($query) use ($postcode) {
$query->where('users_area_coverage.zone_id', $postcode->zone_id);
return $query;
})
->whereHas('workingdays', function ($query) use ($booking) {
$weekday = date('w',strtotime($booking['date']));
$hour = Carbon::now()->format('H:i:s');
$duration = ServiceDuration::find($booking['duration'])->duration;
$hourEnd = Carbon::createFromFormat('H:i:s',$hour)->addMinutes($duration)->format('H:i:s');
if (strtotime($hour)>strtotime($hourEnd))
return $query->where('id','-1');
// dd($hour);
$query->where('dayoff', 0);
$query->where('weekday',$weekday);
$query->whereRaw("TIME(STR_TO_DATE(bo_start, '%H:%i')) <= TIME(STR_TO_DATE('{$hour}','%H:%i')) and TIME(STR_TO_DATE(bo_end, '%H:%i')) >= TIME(STR_TO_DATE('{$hourEnd}','%H:%i'))");
return $query;
})
->whereHas('profile', function ($query) {
$query->where('massage_me_now', 1);
return $query;
})
->whereDoesntHave('daysoff', function ($query) use ($booking) {
// if (!isset($booking['hour']))
// return $query;
$hour = Carbon::now()->format('H:i');
$duration = ServiceDuration::find($booking['duration'])->duration;
$dateHour = $booking['date'].' '.$hour.':00';
$dateHourEnd = $booking['date'].' '.date('H:i',strtotime($hour."+{$duration} minutes")).':00';
$query->whereRaw('STR_TO_DATE("'.$dateHour.'","%Y-%m-%d %H:%i") between date_start and date_end')
->orWhereRaw('STR_TO_DATE("'.$dateHourEnd.'","%Y-%m-%d %H:%i") between date_start and date_end');
// $query->whereRaw('STR_TO_DATE("'.$dateHour.'","%Y-%m-%d %H:%i") between SUBTIME(SUBTIME(date_start,STR_TO_DATE(CONCAT(FLOOR('.$duration.'/60),\':\',MOD('.$duration.',60)),"%h:%i:%s")),"0:15:00") and ADDTIME(ADDTIME(date_end,STR_TO_DATE(CONCAT(FLOOR('.$duration.'/60),\':\',MOD('.$duration.',60)),"%h:%i:%s")),"0:15:00")');
return $query;
})
->whereHas('geoLocation', function($query) use ($booking){
$query->whereRaw("DATE('".date('Y-m-d')."') between DATE(updated_at) and DATE(updated_at)");
return $query;
})
->whereHas('geoLocation', function($query) use ($booking){
$query->whereRaw('"'.date('H:i:0').'" between SUBTIME(TIME(updated_at),"02:30:00") and ADDTIME(TIME(updated_at),"02:30:00")');
return $query;
})
->where(function($query) use ($booking){
$query
->whereDoesntHave('therapistbookings', function($query) use ($booking){
$duration = ServiceDuration::find($booking['duration']);
// $buffer = $duration->duration+0;
$bufferMin = 55;
$buffer_before = $duration->duration+31;
$buffer = $duration->duration+$bufferMin;
$buffer_as_time_before = floor($buffer_before/60).':'.($buffer_before%60);
$buffer_as_time = floor($buffer/60).':'.($buffer%60);
$query
->where('date',date('Y-m-d'))
->where(function($query) use ($booking, $duration, $buffer, $bufferMin){
return $query->whereRaw('
TIME("'.date('H:i').'") BETWEEN SUBTIME(`hour`,STR_TO_DATE(CONCAT(FLOOR('.$buffer.'/60),\':\',MOD('.$buffer.',60)),"%h:%i:%s")) AND ADDTIME(`hour`,STR_TO_DATE(CONCAT(FLOOR((duration+'.$bufferMin.')/60),\':\',MOD((duration+'.$bufferMin.'),60)),"%h:%i:%s"))
');
})
->whereHas('booking',function($query){
return $query->where('is_active',1);
});
// $query->where('date',date('Y-m-d'))
// ->whereRaw('`hour` between SUBTIME("'.date('H:i').'","'.$buffer_as_time_before.'") and ADDTIME(ADDTIME("'.date('H:i').'",STR_TO_DATE(CONCAT(FLOOR('.$duration->duration.'/60),\':\',MOD('.$duration->duration.',60)),"%h:%i")),"'.$buffer_as_time.'")')
//// ->whereRaw('`hour` between SUBTIME(hour,"'.$buffer_as_time_before.'") and ADDTIME(ADDTIME(hour,STR_TO_DATE(CONCAT(FLOOR(duration/60),\':\',MOD(duration,60)),"%h:%i")),"'.$buffer_as_time.'")')
//// ->whereRaw('`hour` between SUBTIME("'.date('H:i').'","00:00") and ADDTIME(ADDTIME("'.date('H:i').'",STR_TO_DATE(CONCAT(FLOOR('.$duration->duration.'/60),\':\',MOD('.$duration->duration.',60)),"%h:%i")),"'.$buffer_as_time.'")')
// ->whereHas('booking',function($query){
// return $query->where('is_active',1);
// });
return $query;
})
->where(function($query) use ($booking){
$query->whereDoesntHave('sessionBlockedTherapists', function($query) use ($booking){
$duration = ServiceDuration::find($booking['duration']);
$buffer_before = $duration->duration+31;
$buffer = $duration->duration+30;
// $buffer = $duration->duration+0;
$buffer_as_time_before = floor($buffer_before/60).':'.($buffer_before%60).':00';
$buffer_as_time = floor($buffer/60).':'.($buffer%60).':00';
$query->where('date',date('Y-m-d'))
->whereRaw('`hour` between SUBTIME("'.date('H:i:0').'","'.$buffer_as_time_before.'") and ADDTIME("'.date('H:i:0').'","'.$buffer_as_time.'")');
});
return $query;
});
return $query;
})
->orderBy('nr_crt')
->get();
// $users = User::OfTherapists()->orderBy('nr_crt')
// ->get();
//delete unavailable selected users
if (isset($booking['selected_therapists'])){
$usersAvailable=[];
foreach($users as $usr)
$usersAvailable[] = $usr->id;
foreach($booking['selected_therapists'] as $key=>$selected){
if (!in_array($selected,$usersAvailable))
unset($booking['selected_therapists'][$key]);
} //ennforeach
Session::put('booking',$booking);
} //endif
//calculate first available hour
foreach($users as $user){
$user->firstAvHour = $this->getFirstHour($user,$booking);
} //endforeach
$checkduration = ServiceDuration::find($booking['duration'])->duration;
foreach($users as $key=>$u){
$userSchedule = $u->workingdays()->where('weekday',$weekday)->get()->first();
if (!$u->firstAvHour)
$users->forget($key);
// if (strtotime($whours->bo_end) < strtotime($u->firstAvHour))
// $users->forget($key);
if (strtotime($userSchedule->bo_end) < strtotime($u->firstAvHour."+{$checkduration} minutes"))
$users->forget($key);
} //endforeach
$sorted = $users->sortBy('firstAvHour');
//return results
return $sorted->values()->all();
}
/**
* Get the first available hour for a specific user
* @param $user
* @param $booking
*/
public function getFirstHour($user,$booking)
{
$result = null;
$fromGeo = [
'lat'=>$user->geoLocation->lat,
'lng'=>$user->geoLocation->lng
];
if (!$fromGeo || !$booking['postcode'])
return $result;
//compose from coordinates
$from = "{$fromGeo['lat']},{$fromGeo['lng']}";
//compose to coordonates
// $response = \GoogleMaps::load('textsearch')
// ->setParam([
// 'query' => "{$booking['postcode']}, London UK",
// ])->get('results'); // return $this
$address = "{$booking['postcode']}, London UK";
$response = \GoogleMaps::load('geocoding')
->setParam (['address' => $address])
->get('results');
if (empty($response['results']))
$to = $address;
else{
$toGeo = $response['results'][0]['geometry']['location'];
$to = "{$toGeo['lat']},{$toGeo['lng']}";
} //endif
$mode = $user->transport_mode;
$eta = $this->gTimeTravel($from,$to,$mode);
if (!$eta || $eta>60)
return null;
//add booking buffer for reservation process: equivalent with the availability in the basket
$eta+=15;
$result = Carbon::now()->addMinutes($eta)->format('H:i');
//return result
return $result;
}
/**
* Calculated estimated time arrival using google maps api: directions
* @param $from
* @param $to
* @param string $mode
* @return mixed
*/
protected function gTimeTravel($from,$to,$mode="DRIVING")
{
$params = [
'origin' => $from,
'destination' => $to,
'mode' => $mode,
'departure_time' => 'now',
];
$direction = \GoogleMaps::load('directions')
->setParam($params)
->get();
$time = json_decode($direction,true);
// dd($time);
if ($time['status']!="OK")
return null;
//get estimated time arrival in minutes
// $buffer = 5;
$buffer = 0;
$eta = ceil($time['routes'][0]['legs'][0]['duration']['value']/60)+$buffer;
//return eta
return $eta;
}
/**
* Therapist bookings
* @return \Illuminate\Support\Collection
*/
public function therapistsbookings()
{
$booking = Session::get('booking');
$users = collect();
//if one of mandatory fields is missing, return empty array results
$mandatory_fields = ['postcode','duration','massage','date'];
foreach($mandatory_fields as $field){
if (!isset($booking[$field]))
return $users;
} //endforeach
//get postcode zone
$postcode = Postcode::where('postcode',$booking['postcode'])->first();
//query therapists
// DB::enableQueryLog();
$users = User::OfTherapists()
->whereHas('servicetypes', function ($query) use ($booking) {
$query->where('users_servicetype.servicetype_id', $booking['massage']);
return $query;
})
->whereHas('zones', function ($query) use ($postcode) {
$query->where('users_area_coverage.zone_id', $postcode->zone_id);
return $query;
})
->whereHas('workingdays', function ($query) use ($booking) {
$weekday = date('w',strtotime($booking['date']));
$query->where('dayoff', 0);
$query->where('weekday',$weekday);
return $query;
})
// ->whereDoesntHave('daysoff', function($query) use ($booking){
// $query->whereRaw("DATE('".$booking["date"]."') between DATE(date_start) and DATE(date_end)");
// return $query;
//// })
// ->whereDoesntHave('daysoff', function ($query) use ($booking) {
// if (!isset($booking['hour']))
// return $query;
//
// $duration = ServiceDuration::find($booking['duration'])->duration;
//
// $dateHour = $booking['date'].' '.$booking['hour'].':00';
// $query->whereRaw('STR_TO_DATE("'.$dateHour.'","%Y-%m-%d %H:%i") between SUBTIME(SUBTIME(date_start,STR_TO_DATE(CONCAT(FLOOR('.$duration.'/60),\':\',MOD('.$duration.',60)),"%h:%i:%s")),"0:15:00") and ADDTIME(ADDTIME(date_end,STR_TO_DATE(CONCAT(FLOOR('.$duration.'/60),\':\',MOD('.$duration.',60)),"%h:%i:%s")),"0:15:00")');
//// $query->whereRaw("STR_TO_DATE('{$dateHour}','%Y-%m-%d %H:%i') between SUBTIME(date_start, STR_TO_DATE(CONCAT(FLOOR({$duration}/60):MOD({$duration},60)),\"%h:%i:%s\"))) and date_end");
//
// return $query;
// })
->whereHas('therapistbookings', function($query) use ($booking){
$query->where('date',$booking['date']);
if (isset($booking['hour']))
$query->whereRaw('`hour` between SUBTIME("'.$booking['hour'].'","00:15:00") and ADDTIME(ADDTIME("'.$booking['hour'].'",STR_TO_DATE(CONCAT(FLOOR(duration/60),\':\',MOD(duration,60)),"%h:%i:%s")),"0:15:00")');
return $query;
})
->get();
// dd(DB::getQueryLog());
// dd($users);
// dd($booking);
//return results
return $users;
}
/**
* Get selected therapists
* @return \Illuminate\Support\Collection
*/
public function selected_therapists()
{
$booking = Session::get('booking');
$users = collect();
//if one of mandatory fields is missing, return empty array results
$mandatory_fields = ['selected_therapists'];
foreach($mandatory_fields as $field){
if (!isset($booking[$field]))
return $users;
} //endforeach
//query therapists
// DB::enableQueryLog();
$users = User::OfTherapists()
->whereIn('id', $booking['selected_therapists'])
->get();
// dd($users);
//return results
return $users;
}
public function therapist_info($thId)
{
$user = User::OfTherapists()
->where('id', $thId)
->first();
if($user)
{
$servicesArray = [];
$services = $user->servicetypes()->where('name','!=','optional')->get();
if($services)
{
foreach ($services as $service)
{
$servicesArray[] = $service->name;
}
}
$therapist['data'] = $user;
$therapist['services'] = $servicesArray;
return $therapist;
}
else
{
return null;
}
}
/**
* Get focal points
*
* @return array
*/
public function focal_points()
{
$points=[];
$focalPoints = FocalPoint::all();
foreach($focalPoints as $fp)
$points[$fp->side][$fp->slug] = ['id'=>$fp->id,'name'=>$fp->name];
//return focal points array
return $points;
}
/**
* Get next 30 days
* @return array
*/
public function available_30_days()
{
$activeDay = Carbon::now()->format('Y-m-d');
$booking = Session::get('booking');
if(isset($booking['date']))
{
$activeDay = $booking['date'];
}
$activeDayTimeStamp = null;
if($activeDay)
{
$activeDayTimeStamp = Carbon::createFromFormat('Y-m-d', $activeDay)->timestamp;
}
$current_30_days = [];
$startDate = Carbon::now();
$startDateTimeStamp = $startDate->timestamp;
$endDate = Carbon::now()->addDays(30);
Carbon::macro('range', function ($startDate, $endDate) {
return new \DatePeriod($startDate, new \DateInterval('P1D'), $endDate);
});
foreach (Carbon::range($startDate, $endDate) as $date) {
$dateTimeStamp = $date->timestamp;
$current_30_days[$dateTimeStamp] = [
'date' => $date->format('Y-m-d'),
'info' => [
'name-day' => substr(strtoupper($date->format('l')),0,3),
'nr-date' => $date->format('d'),
'month-name' => substr($date->format('F'),0,3),
],
'is-active' => false,
'is-available' => true,
];
if($dateTimeStamp == $startDateTimeStamp && !$activeDay)
{
$current_30_days[$dateTimeStamp]['is-active'] = true;
}
elseif($activeDay && ($dateTimeStamp == $activeDayTimeStamp))
{
$current_30_days[$dateTimeStamp]['is-active'] = true;
}
}
return $current_30_days;
}
/**
* Get operation hours
*
* @param $date
* @param null $therapist
* @return array|\Illuminate\Support\Collection
*/
public function all_hours($date,$therapist=null)
{
$booking = Session::get('booking');
$bookingPrice = 0;
if(!isset($booking['duration']) && $this->defaultServiceDuration)
{
Session::set('booking.duration',$this->defaultServiceDuration->id);
$bookingDuration = $this->defaultServiceDuration;
$bookingPrice = $bookingDuration->price;
}
else
{
$bookingDuration = ServiceDuration::find($booking['duration']);
$bookingPrice = $bookingDuration->price;
}
//hours collection
$hours = [];
//get today
$today = Carbon::today();
$today_now = Carbon::now();
//cast current date into Carbon object
$dateC = Carbon::createFromFormat('Y-m-d',$date)->startOfDay();
$diff = $today->diffInHours($dateC,false);
if ($diff<0)
return $hours;
//the buffer between bookings
$buffer = 30;
//if selected date is marked as day off, return empty hours array
$daysOff = $this->days_off($date);
if ($daysOff->count())
return $hours;
//get weekday working hours: if weekday is non working day, return
$weekday = date('w',strtotime($dateC->format('Y-m-d')));
$whours = Schedule::where('weekday',$weekday)->where('open',1)->first();
if (!$whours)
return $hours;
//data curenta este aceeasi cu cea selectata si ultima ora este mai mica decat ora curenta, nmu mai pot alege o ora din ziua dea zi
if ((date('Y-m-d') == date('Y-m-d',strtotime($date))) && (strtotime($whours->bo_end) < strtotime(date('H:i'))))
return $hours;
//create working hours interval collection
$start = strtotime($whours->bo_start);
$end = strtotime($whours->bo_end);
//pentru data curenta, daca este trecut de ora 23, nu mai poate alege nicio ora.
if (date('Y-m-d') == date('Y-m-d',strtotime($date))){
$h = date('H');
$i = date('i');
if ($h==23 and $i>10)
return $hours;
} //endif
$key = date('H:i', $start);
$hours[$key] = [
'available'=>1,
'hour'=>date('H:i', $start),
'price'=>$bookingPrice
];
//add remaining hours
while ($start !== $end)
{
$start = strtotime('+30 minutes',$start);
$key = date('H:i', $start);
$hours[$key] = [
'available'=>1,
'hour'=>date('H:i', $start),
'price'=>$bookingPrice
];
} //endwhile
$results = $hours;
//available hours based on current duration selection and therapist schedule
// if(isset($booking['duration'])){
// $unvhours=[];
// $duration = ServiceDuration::find($booking['duration'])->duration;
// $collection = collect($results);
// $unavailable = $collection->filter(function ($value, $key) {
// return $value['available'] == 0;
// });
//
// $unavailable->all();
// foreach($unavailable as $key=>$value){
// $start_hour = Carbon::createFromFormat('H:i',$key)->subMinutes($duration+$buffer);
// $start = strtotime($start_hour->format('H:i'));
//
// //the starting hour cannot be lower than 8:00am
// if ($start < strtotime("08:00"))
// $start = strtotime("08:00");
//
// //set max hour
// $end = strtotime($key);
//
// $unvhours[date('H:i',$start)] = [
// 'available'=>1,
// 'hour'=>date('H:i', $start)
// ];
// while ($start !== $end)
// {
// $start = strtotime('+30 minutes',$start);
// $key = date('H:i', $start);
// $unvhours[$key] = [
// 'available'=>1,
// 'hour'=>date('H:i', $start)
// ];
// } //endwhile
//
// } //endforeach
//
// $results = array_merge($results,$unvhours);
//
// } //endif
// dd($results);
// asort($results);
//available hours for today based on current time
if ($today->format('Y-m-d') == $dateC->format('Y-m-d')){
//create disabled hours array for today
$inow = Carbon::now()->format('i');
if ($inow>=30)
$next_time = 60-Carbon::now()->format('i')+60;
else
$next_time = 60-Carbon::now()->format('i')+30;
$first_av_hour = Carbon::now()->addMinutes($next_time)->format('H:i');
foreach($results as $hour=>$values){
if (strtotime($hour) < strtotime($first_av_hour)){
$results[$hour]['available'] = 0;
//if hour is set on unavailable time, reset it with the first available hour
if (isset($booking['hour']) && $booking['hour']==$hour){
$booking['hour'] = $first_av_hour;
Session::put('booking',$booking);
}
} //endif
} //ensdforeach
} //endif
//if (selected hour is not available, deselect it and save the new session value)
if (isset($booking['hour']) && @$results[$booking['hour']]['available']==0){
$booking['hour']=null;
unset($booking['hour']);
Session::put('booking',$booking);
} //endif
//return hours
return collect($results);
}
/**
* Process th hours
*
* @param $starth
* @param $endh
* @param array $excepts
* @return array
*/
protected function process_th_hours($starth,$endh,$excepts=[],$th,$date)
{
$booking = Session::get('booking');
$bookingPrice = 0;
if(!isset($booking['duration']) && $this->defaultServiceDuration)
{
Session::set('booking.duration',$this->defaultServiceDuration->id);
$bookingDuration = $this->defaultServiceDuration;
$bookingPrice = $bookingDuration->price;
}
else
{
$bookingDuration = ServiceDuration::find($booking['duration']);
$bookingPrice = $bookingDuration->price;
}
$hours =[];
$start = strtotime($starth);
$end = strtotime($endh);
$currentHourStart = date('H',$start);
$currentMinuteStart = date('i',$start);
if($currentMinuteStart > 0 && $currentMinuteStart < 30)
{
$start = strtotime('+'.(30-$currentMinuteStart).' minutes',$start);
}
elseif ($currentMinuteStart > 30)
{
$start = strtotime('+1 hour',$start);
}
//first hour
$key = date('H:i', $start);
$hours[$key] = [
'available'=>1,
'hour'=>date('H:i', $start),
'price' => $bookingPrice,
'is_booking' => $th->isBookingHour($date, $key)
];
//add remaining hours
while ($start !== $end)
{
$start = strtotime('+30 minutes',$start);
$key = date('H:i', $start);
$hours[$key] = [
'available'=>1,
'hour'=>date('H:i', $start),
'price' => $bookingPrice,
'is_booking' => $th->isBookingHour($date, $key)
];
}
//remove hours
if (!empty($excepts)){
foreach($excepts as $ex){
$hours[$ex]['available']=0;
$hours[$ex]['price']=$bookingPrice;
$hours[$ex]['is_booking']=$th->isBookingHour($date, $ex);
}
}
//return hours
return $hours;
}
/**
* Get operation hours
*
* @param $date
* @param null $therapist
* @return array|\Illuminate\Support\Collection
*/
public function th_hours($date,$therapistId)
{
$booking = Session::get('booking');
$bookingPrice = 0;
if(!isset($booking['duration']) && $this->defaultServiceDuration)
{
Session::set('booking.duration',$this->defaultServiceDuration->id);
$bookingDuration = $this->defaultServiceDuration;
$bookingPrice = $bookingDuration->price;
}
else
{
$bookingDuration = ServiceDuration::find($booking['duration']);
$bookingPrice = $bookingDuration->price;
}
//hours collection
$hours = [];
//get today
$today = Carbon::today();
//cast current date into Carbon object
$dateC = Carbon::createFromFormat('Y-m-d',$date)->startOfDay();
$diff = $today->diffInHours($dateC,false);
if ($diff<0)
return $hours;
//the buffer between bookings
$buffer = 30;
//if selected date is marked as day off, return empty hours array
$daysOff = $this->days_off($date);
if ($daysOff->count())
return $hours;
//get weekday working hours: if weekday is non working day, return
$weekday = date('w',strtotime($dateC->format('Y-m-d')));
$whours = Schedule::where('weekday',$weekday)->where('open',1)->first();
if (!$whours)
return $hours;
//create working hours interval collection
$start = strtotime($whours->bo_start);
$end = strtotime($whours->bo_end);
$key = date('H:i', $start);
$hours[$key] = [
'available'=>0,
'hour'=>date('H:i', $start),
'price'=>$bookingPrice,
'is_booking'=>false
];
//add remaining hours
while ($start !== $end)
{
$start = strtotime('+30 minutes',$start);
$key = date('H:i', $start);
$hours[$key] = [
'available'=>0,
'hour'=>date('H:i', $start),
'price'=>$bookingPrice,
'is_booking'=>false
];
} //endwhile
$therapist = User::where('id',$therapistId)->first();
$th_hours=[];
$twd = $therapist->workingdays()->where('dayoff',0)->where('weekday',$weekday)->first();
if ($twd){
$blockedHours = $therapist->blockedHours($date);
// print_r($blockedHours);
if (count($blockedHours)){
foreach($this->process_th_hours($twd->bo_start,$twd->bo_end,$blockedHours,$therapist,$date) as $key=>$value){
if (isset($th_hours[$key]) && $th_hours[$key]['available']==0)
continue;
else
$th_hours[$key] = $value;
} //endforeach
}
else{
foreach($this->process_th_hours($twd->bo_start,$twd->bo_end,null,$therapist,$date) as $key=>$value){
if (isset($th_hours[$key]) && $th_hours[$key]['available']==0)
continue;
else
$th_hours[$key] = $value;
} //endforeach
}
} //endif
$results = array_merge($hours,$th_hours);
//available hours based on current duration selection and therapist schedule
if(isset($booking['duration'])){
$unvhours=[];
$duration = ServiceDuration::find($booking['duration'])->duration;
$collection = collect($results);
$unavailable = $collection->filter(function ($value, $key) {
return $value['available'] == 0;
});
$unavailable->all();
//dd($unavailable, $results);
foreach ($results as $key => $result)
{
if($result['is_booking'])
{
$addedMinutes = $duration+$buffer;
$subMinutes = $duration+$buffer;
}
else
{
$addedMinutes = $duration;
$subMinutes = 0;
}
$start_hour_after = Carbon::createFromFormat('H:i',$key)->addMinutes($addedMinutes);
$start_after = $start_hour_after->format('H:i');
$start_hour_before = Carbon::createFromFormat('H:i',$key)->subMinutes($subMinutes);
$start_before = $start_hour_before->format('H:i');
$end = strtotime($key);
$start = strtotime($start_before);
if($result['is_booking'])
{
//dd($start_before, $key);
}
//add remaining hours
/*while ($start <= $end)
{
$key = date('H:i', $start);
if(isset($results[$key]))
{
$results[$key]['available'] = 0;
}
$start = strtotime('+30 minutes',strtotime($key));
}*/ //endwhile
$ukeys = [];
if($subMinutes>0)
{
for ($i=$start;$i<=$end;$i=strtotime('+30 minutes',$i))
{
$ukey = date('H:i', $i);
if(isset($results[$ukey]))
{
$results[$ukey]['available'] = 0;
}
$ukeys[] = $ukey;
}
//dd($ukeys);
}
foreach ($unavailable as $k => $item)
{
if(strtotime($start_after) > strtotime($k))
{
$results[$key]['available'] = 0;
$unavailable->pull($k);
break;
}
}
}
} //endif
//available hours for today based on current time
if ($today->format('Y-m-d') == $dateC->format('Y-m-d')){
//create disabled hours array for today
$next_time = 60-Carbon::now()->format('i')+30;
$first_av_hour = Carbon::now()->addMinutes($next_time)->format('H:i');
foreach($results as $hour=>$values){
if (strtotime($hour) < strtotime($first_av_hour)){
$results[$hour]['available'] = 0;
//if hour is set on unavailable time, reset it with the first available hour
if (isset($booking['hour']) && $booking['hour']==$hour){
$booking['hour'] = $first_av_hour;
Session::put('booking',$booking);
}
} //endif
} //ensdforeach
} //endif
//if (selected hour is not available, deselect it and save the new session value)
if (isset($booking['hour']) && @$results[$booking['hour']]['available']==0){
$booking['hour']=null;
unset($booking['hour']);
Session::put('booking',$booking);
} //endif
//return hours
return collect($results);
}
/**
* Get operation hours
*
* @param $date
* @param null $therapist
* @return array|\Illuminate\Support\Collection
*/
public function hours($date,$therapist=null)
{
$booking = Session::get('booking');
$bookingPrice = 0;
if(!isset($booking['duration']) && $this->defaultServiceDuration)
{
Session::set('booking.duration',$this->defaultServiceDuration->id);
$bookingDuration = $this->defaultServiceDuration;
$bookingPrice = $bookingDuration->price;
}
else
{
$bookingDuration = ServiceDuration::find($booking['duration']);
$bookingPrice = $bookingDuration->price;
}
//hours collection
$hours = [];
//get today
$today = Carbon::today();
//cast current date into Carbon object
$dateC = Carbon::createFromFormat('Y-m-d',$date)->startOfDay();
$diff = $today->diffInHours($dateC,false);
if ($diff<0)
return $hours;
//the buffer between bookings
$buffer = 30;
//if selected date is marked as day off, return empty hours array
$daysOff = $this->days_off($date);
if ($daysOff->count())
return $hours;
//get weekday working hours: if weekday is non working day, return
$weekday = date('w',strtotime($dateC->format('Y-m-d')));
$whours = Schedule::where('weekday',$weekday)->where('open',1)->first();
if (!$whours)
return $hours;
//create working hours interval collection
$start = strtotime($whours->bo_start);
$end = strtotime($whours->bo_end);
$key = date('H:i', $start);
$hours[$key] = [
'available'=>0,
'hour'=>date('H:i', $start),
'price'=>$bookingPrice
];
//add remaining hours
while ($start !== $end)
{
$start = strtotime('+30 minutes',$start);
$key = date('H:i', $start);
$hours[$key] = [
'available'=>0,
'hour'=>date('H:i', $start),
'price'=>$bookingPrice
];
} //endwhile
//available hours based on therapist schedule
if ($therapist!=null){
//therapist from the booking or any other specific request
$therapists = User::whereIn('id',$therapist)->get();
}
else{
//available therapists besed on user selection
$therapists = $this->therapists();
}
$th_hours=[];
//select hours only for selected therapists
if (isset($booking['selected_therapists']) && !empty($booking['selected_therapists'])){
$filtered = $therapists->filter(function ($user, $key) use ($booking) {
return in_array($user->id,$booking['selected_therapists']);
});
$therapists = $filtered;
}
foreach($therapists as $therapist){
$twd = $therapist->workingdays()->where('dayoff',0)->where('weekday',$weekday)->first();
if ($twd){
$blockedHours = $therapist->blockedHours($date);
if (count($blockedHours)){
//dd($blockedHours);
foreach($this->process_hours($twd->bo_start,$twd->bo_end,$blockedHours) as $key=>$value){
if (isset($th_hours[$key]) && $th_hours[$key]['available']==0)
continue;
else
$th_hours[$key] = $value;
} //endforeach
}
else{
foreach($this->process_hours($twd->bo_start,$twd->bo_end) as $key=>$value){
if (isset($th_hours[$key]) && $th_hours[$key]['available']==0)
continue;
else
$th_hours[$key] = $value;
} //endforeach
// $th_hours = array_merge($th_hours,$this->process_hours($twd->bo_start,$twd->bo_end));
}
} //endif
} //endforeach
//dd($hours, $th_hours);
$results = array_merge($hours,$th_hours);
//available hours based on current duration selection and therapist schedule
if(isset($booking['duration'])){
$unvhours=[];
$duration = ServiceDuration::find($booking['duration'])->duration;
$collection = collect($results);
$unavailable = $collection->filter(function ($value, $key) {
return $value['available'] == 0;
});
$unavailable->all();
foreach($unavailable as $key=>$value){
$start_hour = Carbon::createFromFormat('H:i',$key)->subMinutes($duration+$buffer);
//$start_hour = Carbon::createFromFormat('H:i',$key);
$start = strtotime($start_hour->format('H:i'));
//the starting hour cannot be lower than 8:00am
if ($start < strtotime("08:00"))
$start = strtotime("08:00");
//set max hour
$end = strtotime($key);
$unvhours[date('H:i',$start)] = [
'available'=>0,
'hour'=>date('H:i', $start),
'price'=>$bookingPrice
];
while($start !== $end){
$start = strtotime('+30 minutes',$start);
$key = date('H:i', $start);
$unvhours[$key] = [
'available'=>0,
'hour'=>date('H:i', $start),
'price'=>$bookingPrice
];
} //endwhile
} //endforeach
//dd($results,$unvhours);
$results = array_merge($results,$unvhours);
} //endif
// asort($results);
//available hours for today based on current time
if ($today->format('Y-m-d') == $dateC->format('Y-m-d')){
//create disabled hours array for today
$next_time = 60-Carbon::now()->format('i')+30;
$first_av_hour = Carbon::now()->addMinutes($next_time)->format('H:i');
foreach($results as $hour=>$values){
if (strtotime($hour) < strtotime($first_av_hour)){
$results[$hour]['available'] = 0;
//if hour is set on unavailable time, reset it with the first available hour
if (isset($booking['hour']) && $booking['hour']==$hour){
$booking['hour'] = $first_av_hour;
Session::put('booking',$booking);
}
} //endif
} //ensdforeach
} //endif
//if (selected hour is not available, deselect it and save the new session value)
if (isset($booking['hour']) && @$results[$booking['hour']]['available']==0){
$booking['hour']=null;
unset($booking['hour']);
Session::put('booking',$booking);
} //endif
//return hours
return collect($results);
}
/**
* Get operation hours
*
* @param $date
* @return array
*/
public function hours_without_buffer($date,$therapist=null)
{
$booking = Session::get('booking');
//hours collection
$hours = [];
//get today
$today = Carbon::today();
//cast current date into Carbon object
$dateC = Carbon::createFromFormat('Y-m-d',$date)->startOfDay();
$diff = $today->diffInHours($dateC,false);
if ($diff<0)
return $hours;
//if selected date is marked as day off, return empty hours array
$daysOff = $this->days_off($date);
if ($daysOff->count())
return $hours;
//get weekday working hours: if weekday is non working day, return
$weekday = date('w',strtotime($dateC->format('Y-m-d')));
$whours = Schedule::where('weekday',$weekday)->where('open',1)->first();
if (!$whours)
return $hours;
//create working hours interval collection
$start = strtotime($whours->bo_start);
$end = strtotime($whours->bo_end);
$key = date('H:i', $start);
$hours[$key] = [
'available'=>0,
'hour'=>date('H:i', $start)
];
//add remaining hours
while ($start !== $end)
{
$start = strtotime('+30 minutes',$start);
$key = date('H:i', $start);
$hours[$key] = [
'available'=>0,
'hour'=>date('H:i', $start)
];
} //endwhile
//available hours based on therapist schedule
if ($therapist!=null){
//therapist from the booking or any other specific request
$therapists = User::whereIn('id',$therapist)->get();
}
else{
//available therapists besed on user selection
$therapists = $this->therapists();
}
$th_hours=[];
//select hours only for selected therapists
if (isset($booking['selected_therapists'])){
$filtered = $therapists->filter(function ($user, $key) use ($booking) {
return in_array($user->id,$booking['selected_therapists']);
});
$therapists = $filtered;
}
foreach($therapists as $therapist){
$twd = $therapist->workingdays()->where('dayoff',0)->where('weekday',$weekday)->first();
if ($twd){
$blockedHours = $therapist->blockedHours($date);
if (count($blockedHours)){
foreach($this->process_hours($twd->bo_start,$twd->bo_end,$blockedHours) as $key=>$value){
if (isset($th_hours[$key]) && $th_hours[$key]['available']==0)
continue;
else
$th_hours[$key] = $value;
} //endforeach
// $th_hours = array_merge($th_hours,$this->process_hours($twd->bo_start,$twd->bo_end,$blockedHours));
}
else{
foreach($this->process_hours($twd->bo_start,$twd->bo_end) as $key=>$value){
if (isset($th_hours[$key]) && $th_hours[$key]['available']==0)
continue;
else
$th_hours[$key] = $value;
} //endforeach
// $th_hours = array_merge($th_hours,$this->process_hours($twd->bo_start,$twd->bo_end));
}
} //endif
} //endforeach
$results = array_merge($hours,$th_hours);
//available hours based on current duration selection and therapist schedule
if(isset($booking['duration'])){
$unvhours=[];
$duration = ServiceDuration::find($booking['duration'])->duration;
$collection = collect($results);
$unavailable = $collection->filter(function ($value, $key) {
return $value['available'] == 0;
});
$unavailable->all();
foreach($unavailable as $key=>$value){
$start_hour = Carbon::createFromFormat('H:i',$key)->subMinutes($duration);
$start = strtotime($start_hour->format('H:i'));
$end = strtotime($key);
$unvhours[date('H:i',$start)] = [
'available'=>0,
'hour'=>date('H:i', $start)
];
// while ($start !== $end)
// {
// $start = strtotime('+30 minutes',$start);
// $key = date('H:i', $start);
// $unvhours[$key] = [
// 'available'=>0,
// 'hour'=>date('H:i', $start)
// ];
// } //endwhile
} //endforeach
$results = array_merge($results,$unvhours);
} //endif
// dd($results);
// asort($results);
//available hours for today based on current time
if ($today->format('Y-m-d') == $dateC->format('Y-m-d')){
//create disabled hours array for today
$next_time = 60-Carbon::now()->format('i')+30;
$first_av_hour = Carbon::now()->addMinutes($next_time)->format('H:i');
foreach($results as $hour=>$values){
if (strtotime($hour) < strtotime($first_av_hour)){
$results[$hour]['available'] = 0;
//if hour is set on unavailable time, reset it with the first available hour
if (isset($booking['hour']) && $booking['hour']==$hour){
$booking['hour'] = $first_av_hour;
Session::put('booking',$booking);
}
} //endif
} //ensdforeach
} //endif
//if (selected hour is not available, deselect it and save the new session value)
if (isset($booking['hour']) && @$results[$booking['hour']]['available']==0){
$booking['hour']=null;
unset($booking['hour']);
Session::put('booking',$booking);
} //endif
//return hours
return collect($results);
}
/**
* Process hours
*
* @param $starth
* @param $endh
* @param array $excepts
* @return array
*/
protected function process_hours($starth,$endh,$excepts=[])
{
$booking = Session::get('booking');
$bookingPrice = 0;
if(!isset($booking['duration']) && $this->defaultServiceDuration)
{
Session::set('booking.duration',$this->defaultServiceDuration->id);
$bookingDuration = $this->defaultServiceDuration;
$bookingPrice = $bookingDuration->price;
}
else
{
$bookingDuration = ServiceDuration::find($booking['duration']);
$bookingPrice = $bookingDuration->price;
}
$hours =[];
$start = strtotime($starth);
$end = strtotime($endh);
$currentHourStart = date('H',$start);
$currentMinuteStart = date('i',$start);
if($currentMinuteStart > 0 && $currentMinuteStart < 30)
{
$start = strtotime('+'.(30-$currentMinuteStart).' minutes',$start);
}
elseif ($currentMinuteStart > 30)
{
$start = strtotime('+1 hour',$start);
}
//first hour
$key = date('H:i', $start);
$hours[$key] = [
'available'=>1,
'hour'=>date('H:i', $start),
'price' => $bookingPrice,
];
//add remaining hours
while ($start !== $end)
{
$start = strtotime('+30 minutes',$start);
$key = date('H:i', $start);
$hours[$key] = [
'available'=>1,
'hour'=>date('H:i', $start),
'price' => $bookingPrice
];
}
//remove hours
if (!empty($excepts)){
foreach($excepts as $ex){
$hours[$ex]['available']=0;
$hours[$ex]['price']=$bookingPrice;
// unset($hours[$ex]);
}
}
//return hours
return $hours;
}
/**
* Check if a date is a non-working day
*/
public function days_off($start_date=null)
{
//set date
if (!$start_date)
$start_date = date('Y-m-d 00:00:00');
else
$start_date = Carbon::createFromFormat('Y-m-d',$start_date)->format('Y-m-d H:i:s');
//query selected date between non working days
$nwdays = ScheduleDaysOff::whereRaw("'".$start_date."' between date_start and date_end")->get();
//return results: non working days
return $nwdays;
}
public function getAndSetFirstAvailableDayHour()
{
$booking = Session::get('booking');
if (!isset($booking['date']))
{
$date = date('Y-m-d');
}
else
{
$date = $booking['date'];
}
$hours = $this->all_hours($date);
$firstHour = null;
if($hours)
{
foreach ($hours as $hour)
{
if($hour['available'])
{
$firstHour = $hour;
break;
}
}
if($firstHour)
{
Session::set('booking.hour',$firstHour['hour']);
return $firstHour;
}
}
}
/**
* Get available days
*
* @return array
*/
public function days()
{
$days=[];
//todo
//return dates
return $days;
}
/**
* Get Order Details by Card transaction id
* @param $card_trans_id
*/
public function get_order_cart($card_trans_id)
{
return BookingOrder::where('card_trans_id',$card_trans_id)->get();
}
/**
* Return if the booking can be cancelled
* @param $id
* @return bool
*/
public function can_be_safe_canceled(BookingOrder $obj)
{
//default response value
$response = false;
//get order info
$orderInfo = json_decode($obj->orderInfo,true);
//if in the order has been used an voucher code, the amount is not refundable
// if ($orderInfo['has_voucher'])
// return $response=false;
$now = Carbon::now();
$dateHourOrder = $obj->date->format('Y-m-d').' '.$obj->hour;
$orderTime = Carbon::createFromFormat('Y-m-d H:i',$dateHourOrder);
//if the cancellation is done by the client in less than 3 hours before the booking, the amount is not refundable
$safe_cancel = $now->diffInMinutes($orderTime,false);
if ($safe_cancel>90){
$response=true;
}
else{
$response=false;
}
//return response
return $response;
}
/**
* Cancel order and refund value
* @param BookingOrder $obj
*/
public function cancel_order(BookingOrder $obj, $admin=false)
{
//start transaction
DB::beginTransaction();
//first refund the value
$refundStatus = $this->refund_value_of($obj,$admin);
$orderInfo = json_decode($obj->orderInfo,true);
$therapistsIds = $orderInfo['therapistIds'];
//cancel order
$obj->is_active=0;
$success = $obj->save();
//refund voucher and cvancel invoice only if the booking can be safe canceled
if ($this->can_be_safe_canceled($obj)){
//refund voucher value
$refundVoucher = $this->refund_voucher_of($obj,$admin);
//refund invoice
$refundInvoice = $this->cancel_invoice_of($obj);
} //end
//add mobile app notifications to the client and therepists
//compose message
$notif_message = trans("schedules::booking.mobile_cancel_order",['number'=>$obj->id,'date'=>$obj->date_to_human,'hour'=>$obj->hour_to_human]);
//notification users array
$notif_users[] = $obj->user_id;
foreach($therapistsIds as $thid)
$notif_users[] = $thid;
//store notifications
foreach($notif_users as $user)
NotifRepository::add($user,$notif_message, 'cancelBooking', 'Booking cancelled');
//commit-rollback transaction
if ($success){
//commit
DB::commit();
//send confirmation email
$user = User::findOrFail($obj->user_id);
$data['user'] = $user;
$data['order'] = $obj;
Mail::send('schedules::frontend.emails.cancelorder', ['user' => $user, 'order'=>$obj], 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('Zen London Massage website – cancel booking #'.$data['order']->id);
});
//send therapist email confirmation
//send confirmation email
$thusers = User::whereIn('id',$notif_users)->get();
foreach($thusers as $therapist){
$data['user'] = $therapist;
Mail::send('schedules::frontend.emails.therapist_cancelorder', ['user' => $therapist, 'order'=>$obj], 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').' – cancel booking #'.$data['order']->id);
});
}
}
else
{
//rollback actions
DB::rollBack();
} //end elseif transaction
//create response array
$response = [
'success' => $success,
'message' => $refundStatus['message'],
];
//return response
return $response;
}
/**
* Refund payments with credit card
* @param BookingOrder $obj
* @return bool
*/
protected function refund_value_of(BookingOrder $obj, $admin=false)
{
$response = [
'success'=>false,
'message'=>null,
];
if (!$admin){
$safe_cancel = $this->can_be_safe_canceled($obj);
$response = [
'success'=>false,
'message'=>null,
];
}
else
$safe_cancel=true;
//to refund, all the conditions must be valid
// if (!$safe_cancel || !$obj->card_trans_id || !$obj->card_trans_status || !$obj->amount>0 || !$obj->is_active)
// return $response;
//if the booking was paid by cash
if (!$safe_cancel && empty($obj->card_trans_id) && $obj->amount>0 && $obj->is_active){
$response['message'] = $this->charge_from_card($obj);
return $response;
} //end
//The Booking was paid with card and cannot be canceled.
if (!$obj->card_trans_id || !$obj->card_trans_status || !($obj->amount>0) || !$obj->is_active || !$safe_cancel)
return $response;
// Try to refund the amount
try{
//according with sagepay, refund is available only for yesterday
if ($obj->created_at->format('Y-m-d') != date('Y-m-d'))
$response = $this->opt_refund($obj);
else
$response = $this->opt_void($obj);
// //BRAINTREE first find breintree transaction
// $trans = Transaction::find($obj->card_trans_id);
//
// //then select method based on transaction status
// switch ($trans->status){
// case 'settled':
// case 'settling':
// $response = $this->opt_refund($obj);
// break;
// case 'submitted_for_settlement':
// $response = $this->opt_void($obj);
// break;
// default:
// $response = $this->opt_void($obj);
// break;
// } //endwitch
}
catch(\Exception $e){
//the transaction id not found
$response['message'] = $e->getMessage();
}
//return message
return $response;
}
/**
* Charge money from card
* @param $obj
*/
public function charge_from_card($obj)
{
//todo: for the moment, just return null.
return null;
$user = User::find($obj->user_id);
$message = '';
//check if user exists
if (!$user)
return $message;
//user has no valid card defined
if (!$user->braintree_id) {
$message = strtoupper("You have no valid card defined. Please enter one below!");
return $message;
} //endif
try {
$name = "massage services";
$total = $obj->amount;
$response = $user->invoiceFor($name,$total);
} catch (\Exception $e) {
$message = $e->getMessage();
$message = str_ireplace('braintree','Zen London',$message);
return $message;
}
//update transaction type from cash to card
$data = [
'card_trans_id' => $response->transaction->id,
'card_trans_status' => (bool)$response->success,
'card_details' => json_encode([
'customerLocation' => $response->transaction->creditCardDetails->customerLocation,
'cardType' => $response->transaction->creditCardDetails->cardType,
'expirationDate' => $response->transaction->creditCardDetails->expirationDate,
'imageUrl' => $response->transaction->creditCardDetails->imageUrl,
'maskedNumber' => $response->transaction->creditCardDetails->maskedNumber,
'last4' => $response->transaction->creditCardDetails->last4,
'bin' => $response->transaction->creditCardDetails->bin,
]),
];
//update transaction type
$obj->update($data);
}
/**
* Refund voucher value of booking order
* @param BookingOrder $obj
* @param bool $admin
*/
protected function refund_voucher_of(BookingOrder $obj, $admin=false)
{
$response = [
'success'=>false,
'message'=>null,
];
$info = json_decode($obj->orderInfo,true);
if (!$admin){
$safe_cancel = $this->can_be_safe_canceled($obj);
$response = [
'success'=>false,
'message'=>null,
];
}
else
$safe_cancel=true;
//to refund voucher value, all conditions must be true
if (!$safe_cancel || !$info['has_voucher'] || !$info['price_net'] || !$info['voucher']['code'])
return $response;
//continue with voucher value refund
$qty=1;
switch($info['therapistsOpt']){
case '4hands':
$qty = 1;
break;
default:
$qty=1;
break;
} //end switch
$voucherRepo = new VoucherRepository();
$status = $voucherRepo->refund_value($info['voucher']['code'],$info['price_net'],$qty);
//cancel invoice
$response = [
'success' => $status['status'],
'message' => $status['message'],
];
//return response
return $response;
}
/**
* Refund Function
* @param $obj
* @return array
*/
protected function opt_refund($obj)
{
$gateway = Omnipay::create('SagePay\Direct');
$gateway->setVendor(env('SAGEPAY_VENDOR_NAME'));
$gateway->setTestMode(env('SAGEPAY_TEST_MODE'));
$payload = json_decode($obj->card_trans_id,true);
$result = $gateway->refund(array(
'useAuthenticate' => false,
'transactionReference' => $obj->card_trans_id,
'transactionId' => $payload['VendorTxCode'].'-REF',
'amount' => $obj->amount,
'currency' => env('SAGEPAY_CCY'),
'description' => 'Massage services cancelled',
))->send();
$response = [
'success'=>$result->isSuccessful(),
'message'=>(!$result->isSuccessful())?$result->getMessage():trans('schedules::booking.text_successfully_refunded'),
];
return $response;
}
/**
* Void Function
* @param $obj
* @return array
*/
protected function opt_void($obj)
{
$gateway = Omnipay::create('SagePay\Direct');
$gateway->setVendor(env('SAGEPAY_VENDOR_NAME'));
$gateway->setTestMode(env('SAGEPAY_TEST_MODE'));
$result = $gateway->void(array(
'useAuthenticate' => false,
'transactionReference' => $obj->card_trans_id,
'amount' => $obj->amount,
'currency' => env('SAGEPAY_CCY'),
'description' => 'Massage services cancelled',
))->send();
$orderInfo = json_decode($obj->orderInfo,true);
//void the extension
if ($orderInfo['has_extension'] && array_key_exists('extension',$orderInfo)){
$ext_result = $gateway->void(array(
'useAuthenticate' => false,
'transactionReference' => $orderInfo['extension']['card_details']['transaction_reference'],
'amount' => $orderInfo['extension']['price'],
'currency' => env('SAGEPAY_CCY'),
'description' => 'Massage services - extension cancelled',
))->send();
} //end void the extension
$response = [
'success'=>$result->isSuccessful(),
'message'=>(!$result->isSuccessful())?$result->getMessage():trans('schedules::booking.text_successfully_refunded'),
];
return $response;
}
/**
* Cancel invoice of booking order
*/
public function cancel_invoice_of($obj)
{
$status = false;
$invoice = $obj->invoice;
if (!$invoice)
return $status;
$repoInv = new BookingInvoiceRepository();
$status = $repoInv->cancel_invoice($invoice->id);
return $status;
}
/**
* Set saved booking data into session
* @param $obj
*/
public function set_booking_data($obj)
{
//first unset any booking data
$this->unset_booking_data();
//get info of booking details
$info = json_decode($obj->orderInfo,true);
//set new data
$data = [
'postcode' => $info['postcode'],
'duration' => $info['duration_id'],
'massage' => $info['massage_type_id'],
'date' => $obj->date->format('Y-m-d'),
'hour' => $obj->hour,
'selected_therapists' => $info['therapistIds'],
'therapists_opt' => $info['therapistsOpt'],
'therapists' => $info['therapistsNo'],
'type' => $info['type'],
];
//store new data into session
Session::put('booking',$data);
}
/**
* Set saved booking data into session
* @param $obj
*/
public function unset_booking_data()
{
Session::forget('booking');
}
/**
* User can extends thier booking with another service
*
* @param $booking
* @param $service
* @return bool
*/
public function can_extend_with($booking,$service)
{
//default status
$status = false;
//get booking therapists
$therapists = $booking->therapists;
//add extention time to the current booking + 15min buffer to check if booking will overlaps
$addTime = $booking->duration_min+$service->duration+58;
$addTime2 = $booking->duration_min+$service->duration;
//calculate diff in minutes between end of massage session and current time
$bookingEndTime = Carbon::createFromFormat('Y-m-d H:i',"{$booking->date->format('Y-m-d')} {$booking->hour}")->addMinutes($booking->duration_min);
$diff = $bookingEndTime->diffInMinutes(Carbon::now(),false);
$bookingEndTime2 = Carbon::createFromFormat('Y-m-d H:i',"{$booking->date->format('Y-m-d')} {$booking->hour}")->addMinutes($addTime2)->format('Y-m-d H:i');
//check if extension ca be made regarding the therapist schedule
$weekday = date('w',strtotime($booking->date));
foreach($therapists as $th){
$thWeekDaySchedule = $th->workingdays()->where('weekday',$weekday)->get()->first();
if (!$thWeekDaySchedule)
continue;
$endOfSchedule = Carbon::createFromFormat('Y-m-d H:i A',"{$booking->date->format('Y-m-d')} {$thWeekDaySchedule->bo_end}")->format('Y-m-d H:i');
$diffEndOfSchedule = strtotime($endOfSchedule) - strtotime($bookingEndTime2);
// dd([
// '$thWeekDaySchedule'=>$thWeekDaySchedule,
// '$endOfSchedule'=>$endOfSchedule,
// '$bookingEndTime' => $bookingEndTime2,
// '$diffEndOfSchedule'=>$diffEndOfSchedule,
// ]);
if ($diffEndOfSchedule < 0)
return false;
} //endforeach
//if the current time is bigger than the booking session time, add minutes which passed over session booking end time to the addTime variable.
//this will
if ($diff>0)
$addTime += $diff;
$timewithbuffer = floor($addTime/60).':'.($addTime%60);
$count = 0;
//for each therapist, check if selected service-extension overlap on another booking
foreach($therapists as $trp){
// DB::enableQueryLog();
$thBookings = $trp->therapistbookings()
->where('date','=',$booking->date->format('Y-m-d'))
->whereRaw('hour between SUBTIME("'.$booking->hour.'","00:15") and ADDTIME("'.$booking->hour.'" ,"'.$timewithbuffer.'")')
->where('booking_id','!=',$booking->id)
->whereHas('booking',function($query){
return $query->where('is_active',1);
})
->get();
// dd(DB::getQueryLog());
$count += $thBookings->count();
//todo: check if other booking is in the session basket
} //endforeach
//if the therapists has bookings, deny extension
if ($count)
return $status;
//if the therapists has no other bookings, let the user to extend his session
$status = true;
//return status
return $status;
}
/**
* Therapist can delay the booking with number of minutes (@param delay)
* @param $booking
* @param int $delay
* @return bool
*/
public function can_delay_with($booking,$delay)
{
//default status
$status = false;
$delay = (int)$delay;
//get booking therapists
$therapists = $booking->therapists;
//add delay time to the current booking + 15min buffer to determine if booking will overlaps
$addTime = $booking->duration_min+$delay+15;
//calculate diff in minutes between end of massage session and current time
$bookingEndTime = Carbon::createFromFormat('Y-m-d H:i',"{$booking->date->format('Y-m-d')} {$booking->hour}")->addMinutes($booking->duration_min);
$diff = $bookingEndTime->diffInMinutes(Carbon::now(),false);
//if the current time is bigger than the booking session time, add minutes which passed over session booking end time to the addTime variable.
//this will
if ($diff>0)
$addTime += $diff;
$timewithbuffer = floor($addTime/60).':'.($addTime%60);
$count = 0;
//for each therapist, check if selected service-extension overlap on another booking
foreach($therapists as $trp){
// DB::enableQueryLog();
$thBookings = $trp->therapistbookings()
->where('date','=',$booking->date->format('Y-m-d'))
->whereRaw('hour between SUBTIME("'.$booking->hour.'","00:15") and ADDTIME("'.$booking->hour.'" ,"'.$timewithbuffer.'")')
->where('booking_id','!=',$booking->id)
->whereHas('booking',function($query){
return $query->where('is_active',1);
})
->get();
// dd(DB::getQueryLog());
$count += $thBookings->count();
//todo: check if other booking is in the session basket
} //endforeach
//if the therapists has bookings, deny extension
if ($count)
return $status;
//if the therapists has no other bookings, let the user to extend his session
$status = true;
//return status
return $status;
}
/**
* Start booking threading
* @param $booking
*/
public function create_thread($booking)
{
$subject = $booking->treadsubject;
$thread = Thread::where('subject',$subject)->first();
//create the thread if not exists
if (!$thread)
{
$thread = Thread::create(
[
'subject' => $subject,
]
);
} //endif
// create message
Message::create(
[
'thread_id' => $thread->id,
'user_id' => $booking->user_id,
'body' => trans('schedules::booking.default_message_thread'),
]
);
// Add replier as a participant
$participant = Participant::firstOrCreate(
[
'thread_id' => $thread->id,
'user_id' => $booking->user_id,
]
);
$participant->last_read = new Carbon();
$participant->save();
//add recipients: is this case the recipients are the therapists
foreach($booking->therapists as $rec)
$recipients[] = $rec->id;
if (!empty($recipients))
$thread->addParticipant($recipients);
} //end method
public function checkPhoneNumber($phone)
{
$phone = trim($phone);
$phone = preg_replace("/[^0-9]/", "",$phone);
$phoneLen = strlen($phone);
$firstDigit = substr($phone,0,1);
if($phoneLen >= 10 && $phoneLen<=14 && $firstDigit==0)
{
return true;
}
else
{
return false;
}
}
}