Quellcode durchsuchen

Add pro->getAvailabilityEvents()

Vijayakrishnan vor 4 Jahren
Ursprung
Commit
ad258a58fb
4 geänderte Dateien mit 276 neuen und 58 gelöschten Zeilen
  1. 50 0
      app/Helpers/TimeLine.php
  2. 44 4
      app/Helpers/helpers.php
  3. 22 54
      app/Http/Controllers/AppointmentController.php
  4. 160 0
      app/Models/Pro.php

+ 50 - 0
app/Helpers/TimeLine.php

@@ -55,6 +55,10 @@ class TimeLine {
         });
         $this->normalize();
         $this->vdump($this->available);
+
+        // add to unavailable
+        $this->unavailable[] = new TimeSlot($_start, $_end);
+        // $this->normalizeUnavailable();
     }
 
     private function removeEmbeddedInAvailSlot($removeStart, $removeEnd) {
@@ -193,6 +197,52 @@ class TimeLine {
 
     }
 
+    private function normalizeUnavailable() {
+
+        $allDone = true;
+
+        for ($i=0; $i<count($this->unavailable)-1; $i++) {
+            if($this->unavailable[$i]->end >= $this->unavailable[$i+1]->start && // ends in the middle of next slot
+                $this->unavailable[$i]->end <= $this->unavailable[$i+1]->end)
+            {
+                // extend self & delete next
+                $this->unavailable[$i]->end = $this->unavailable[$i+1]->end;
+                array_splice($this->unavailable, $i+1, 1);
+                $allDone = false;
+                break;
+            }
+
+            if($this->unavailable[$i]->end >= $this->unavailable[$i+1]->end) // ends after next slot end
+            {
+                // delete next
+                array_splice($this->unavailable, $i+1, 1);
+                $allDone = false;
+                break;
+            }
+
+            if($this->unavailable[$i]->start >= $this->unavailable[$i]->end) // starts and ends at the same time!
+            {
+                // delete self
+                array_splice($this->unavailable, $i, 1);
+                $allDone = false;
+                break;
+            }
+        }
+
+        if(!$allDone) {
+            $this->normalizeUnavailable(); // recurse till clean
+        }
+
+    }
+
+    public function getAvailable() {
+        return $this->available;
+    }
+
+    public function getUnavailable() {
+        return $this->unavailable;
+    }
+
     public function vdump($_x) {
 //        echo "<pre>";
 //        print_r($_x);

+ 44 - 4
app/Helpers/helpers.php

@@ -51,7 +51,7 @@ if(!function_exists('friendly_date_time_short_with_tz')) {
             $realTimezone = resolve_timezone($tz);
             $date = new DateTime($value);
             $date->setTimezone(new DateTimeZone($realTimezone));
-            
+
             return $date->format("m/d/y" . ($includeTime ? ", h:iA" : ""));
 
         }
@@ -92,12 +92,12 @@ if(!function_exists('friendly_time')) {
 
 if(!function_exists('military_time')) {
     function military_time($value,  $tz='UTC', $default = '-') {
-        
+
         if(!$value || empty($value)) return $default;
         try {
             $realTimezone = resolve_timezone($tz);
-            $date = new DateTime($value);  
-            $date->setTimezone(new DateTimeZone($realTimezone));          
+            $date = new DateTime($value);
+            $date->setTimezone(new DateTimeZone($realTimezone));
             return $date->format("H:i");
         }
         catch (Exception $e) {
@@ -283,3 +283,43 @@ if(!function_exists('getVal')) {
         }
     }
 }
+
+if(!function_exists('appTZtoPHPTZ')) {
+    function appTZtoPHPTZ($_timezone)
+    {
+        switch ($_timezone) {
+            case 'ALASKA':
+                $timezone = "US/Alaska";
+                break;
+            case 'CENTRAL':
+                $timezone = "US/Central";
+                break;
+            case 'HAWAII':
+                $timezone = "US/Hawaii";
+                break;
+            case 'MOUNTAIN':
+                $timezone = "US/Mountain";
+                break;
+            case 'PACIFIC':
+                $timezone = "US/Pacific";
+                break;
+            case 'PUERTO_RICO':
+                $timezone = "America/Puerto_Rico";
+                break;
+            default:
+                $timezone = "US/Eastern";
+                break;
+        }
+        return $timezone;
+    }
+}
+
+if(!function_exists('convertToTimezone')) {
+    function convertToTimezone($_dateTime, $_targetTimezone, $_sourceTimezone = 'UTC', $_returnRaw = false)
+    {
+        if (!$_dateTime) return $_dateTime;
+        $date = new \DateTime($_dateTime, new \DateTimeZone($_sourceTimezone));
+        $date->setTimezone(new \DateTimeZone(appTZtoPHPTZ($_targetTimezone)));
+        return $_returnRaw ? $date : $date->format('Y-m-d H:i:s');
+    }
+}

+ 22 - 54
app/Http/Controllers/AppointmentController.php

@@ -63,8 +63,8 @@ class AppointmentController extends Controller
                 "clientUid" => $appointment->client->uid,
                 "proId" => $appointment->pro->id,
                 "proUid" => $appointment->pro->uid,
-                "start" => $this->convertToTimezone($appointment->start_time, $timeZone),
-                "end" => $this->convertToTimezone($appointment->end_time, $timeZone),
+                "start" => convertToTimezone($appointment->start_time, $timeZone),
+                "end" => convertToTimezone($appointment->end_time, $timeZone),
                 "clientOnly" => !in_array($appointment->pro->id, $proIds),
                 "otherClient" => ($appointment->client->id != $clientId),
                 "status" => $appointment->status,
@@ -120,9 +120,10 @@ class AppointmentController extends Controller
             // 3. calculate pairs of start-end of availability
 
             // 1. enumerate days between start and end (inclusive)
-            $phpTZ = $this->appTZtoPHPTZ($timeZone);
-            $startDate = new \DateTime($start, new \DateTimeZone($phpTZ));
-            $endDate = new \DateTime($end, new \DateTimeZone($phpTZ));
+            $phpTZ = appTZtoPHPTZ($timeZone);
+            $phpTZObject = new \DateTimeZone($phpTZ);
+            $startDate = new \DateTime($start, $phpTZObject);
+            $endDate = new \DateTime($end, $phpTZObject);
             $endDate->setTime(23, 59, 59);
             $period = new \DatePeriod($startDate, \DateInterval::createFromDateString('1 day'), $endDate);
             $days = [];
@@ -172,15 +173,15 @@ class AppointmentController extends Controller
                     });
                     foreach ($proGenAvailForTheDay as $ga) {
 
-                        $gaStart = new \DateTime($day["date"], new \DateTimeZone($this->appTZtoPHPTZ($ga->timezone)));
+                        $gaStart = new \DateTime($day["date"], new \DateTimeZone(appTZtoPHPTZ($ga->timezone)));
                         $parts = explode(":", $ga->start_time);
                         $gaStart->setTime(intval($parts[0]), intval($parts[1]), intval($parts[2]));
-                        $gaStart->setTimezone(new \DateTimeZone($phpTZ));
+                        $gaStart->setTimezone($phpTZObject);
 
-                        $gaEnd = new \DateTime($day["date"], new \DateTimeZone($this->appTZtoPHPTZ($ga->timezone)));
+                        $gaEnd = new \DateTime($day["date"], new \DateTimeZone(appTZtoPHPTZ($ga->timezone)));
                         $parts = explode(":", $ga->end_time);
                         $gaEnd->setTime(intval($parts[0]), intval($parts[1]), intval($parts[2]));
-                        $gaEnd->setTimezone(new \DateTimeZone($phpTZ));
+                        $gaEnd->setTimezone($phpTZObject);
 
                         $proTimeLine->addAvailability($gaStart, $gaEnd);
                     }
@@ -189,19 +190,19 @@ class AppointmentController extends Controller
 
                 // specific availability
                 foreach ($proSpecAvail as $sa) {
-                    $saStart = new \DateTime($sa->start_time, new \DateTimeZone($this->appTZtoPHPTZ($sa->timezone)));
-                    $saStart->setTimezone(new \DateTimeZone($phpTZ));
-                    $saEnd = new \DateTime($sa->end_time, new \DateTimeZone($this->appTZtoPHPTZ($sa->timezone)));
-                    $saEnd->setTimezone(new \DateTimeZone($phpTZ));
+                    $saStart = new \DateTime($sa->start_time, new \DateTimeZone(appTZtoPHPTZ($sa->timezone)));
+                    $saStart->setTimezone($phpTZObject);
+                    $saEnd = new \DateTime($sa->end_time, new \DateTimeZone(appTZtoPHPTZ($sa->timezone)));
+                    $saEnd->setTimezone($phpTZObject);
                     $proTimeLine->addAvailability($saStart, $saEnd);
                 }
 
                 // specific unavailability
                 foreach ($proSpecUnavail as $sua) {
-                    $suaStart = new \DateTime($sua->start_time, new \DateTimeZone($this->appTZtoPHPTZ($sua->timezone)));
-                    $suaStart->setTimezone(new \DateTimeZone($phpTZ));
-                    $suaEnd = new \DateTime($sua->end_time, new \DateTimeZone($this->appTZtoPHPTZ($sua->timezone)));
-                    $suaEnd->setTimezone(new \DateTimeZone($phpTZ));
+                    $suaStart = new \DateTime($sua->start_time, new \DateTimeZone(appTZtoPHPTZ($sua->timezone)));
+                    $suaStart->setTimezone($phpTZObject);
+                    $suaEnd = new \DateTime($sua->end_time, new \DateTimeZone(appTZtoPHPTZ($sua->timezone)));
+                    $suaEnd->setTimezone($phpTZObject);
                     $proTimeLine->removeAvailability($suaStart, $suaEnd);
                 }
 
@@ -211,8 +212,8 @@ class AppointmentController extends Controller
                 });
                 foreach ($proAppointments as $appointment) {
                     if ($appointment->start_time && $appointment->end_time) {
-                        $appStart = $this->convertToTimezone($appointment->start_time, $timeZone, 'UTC', true);
-                        $appEnd = $this->convertToTimezone($appointment->end_time, $timeZone, 'UTC', true);
+                        $appStart = convertToTimezone($appointment->start_time, $timeZone, 'UTC', true);
+                        $appEnd = convertToTimezone($appointment->end_time, $timeZone, 'UTC', true);
                         $proTimeLine->removeAvailability($appStart, $appEnd);
                     }
                 }
@@ -220,10 +221,10 @@ class AppointmentController extends Controller
                 foreach ($proTimeLine->available as $item) {
 
                     $eStart = new \DateTime('@' . $item->start);
-                    $eStart->setTimezone(new \DateTimeZone($phpTZ));
+                    $eStart->setTimezone($phpTZObject);
 
                     $eEnd = new \DateTime('@' . $item->end);
-                    $eEnd->setTimezone(new \DateTimeZone($phpTZ));
+                    $eEnd->setTimezone($phpTZObject);
 
                     $events[] = [
                         "type" => "availability",
@@ -244,37 +245,4 @@ class AppointmentController extends Controller
         return json_encode($events);
     }
 
-    private function convertToTimezone($_dateTime, $_targetTimezone, $_sourceTimezone = 'UTC', $_returnRaw = false) {
-        if(!$_dateTime) return $_dateTime;
-        $date = new \DateTime($_dateTime, new \DateTimeZone($_sourceTimezone));
-        $date->setTimezone(new \DateTimeZone($this->appTZtoPHPTZ($_targetTimezone)));
-        return $_returnRaw ? $date : $date->format('Y-m-d H:i:s');
-    }
-
-    private function appTZtoPHPTZ($_timezone) {
-        switch($_timezone) {
-            case 'ALASKA':
-                $timezone = "US/Alaska";
-                break;
-            case 'CENTRAL':
-                $timezone = "US/Central";
-                break;
-            case 'HAWAII':
-                $timezone = "US/Hawaii";
-                break;
-            case 'MOUNTAIN':
-                $timezone = "US/Mountain";
-                break;
-            case 'PACIFIC':
-                $timezone = "US/Pacific";
-                break;
-            case 'PUERTO_RICO':
-                $timezone = "America/Puerto_Rico";
-                break;
-            default:
-                $timezone = "US/Eastern";
-                break;
-        }
-        return $timezone;
-    }
 }

+ 160 - 0
app/Models/Pro.php

@@ -4,6 +4,9 @@ namespace App\Models;
 
 # use Illuminate\Database\Eloquent\Model;
 
+use App\Helpers\TimeLine;
+use Exception;
+
 class Pro extends Model
 {
     protected $table = 'pro';
@@ -99,4 +102,161 @@ class Pro extends Model
     public function canvasCustomItems($_key) {
         return ClientCanvasDataCustomItem::where('key', $_key)->get();
     }
+
+
+    /**
+     * @param $_start - YYYY-MM-DD
+     * @param $_end - YYYY-MM-DD
+     * @param string $_timezone - defaults to EASTERN
+     * @param string $_availableBG - defaults to #00a
+     * @param string $_unavailableBG - defaults to #a00
+     * @return array
+     * @throws Exception
+     */
+    public function getAvailabilityEvents($_start, $_end, $_timezone = 'EASTERN', $_availableBG = '#00a', $_unavailableBG = '#a00') {
+
+        $_start .= ' 00:00:00';
+        $_end .= ' 23:59:59';
+
+        // get availability data
+        $proGenAvail = ProGeneralAvailability
+            ::where('is_cancelled', false)
+            ->where('pro_id', $this->id)
+            ->get();
+        $proSpecAvail = ProSpecificAvailability
+            ::where('is_cancelled', false)
+            ->where('pro_id', $this->id)
+            ->where(function ($query) use ($_start, $_end) {
+                $query
+                    ->where(function ($query2) use ($_start, $_end) {
+                        $query2
+                            ->where('start_time', '>=', $_start)
+                            ->where('start_time', '<=', $_end);
+                    })
+                    ->orWhere(function ($query2) use ($_start, $_end) {
+                        $query2
+                            ->where('end_time', '>=', $_start)
+                            ->where('end_time', '<=', $_end);
+                    });
+            })
+            ->get();
+        $proSpecUnavail = ProSpecificUnavailability
+            ::where('is_cancelled', false)
+            ->where('pro_id', $this->id)
+            ->where(function ($query) use ($_start, $_end) {
+                $query
+                    ->where(function ($query2) use ($_start, $_end) {
+                        $query2
+                            ->where('start_time', '>=', $_start)
+                            ->where('start_time', '<=', $_end);
+                    })
+                    ->orWhere(function ($query2) use ($_start, $_end) {
+                        $query2
+                            ->where('end_time', '>=', $_start)
+                            ->where('end_time', '<=', $_end);
+                    });
+            })
+            ->get();
+
+        // default GA
+        // if no gen avail, assume mon to fri, 9 to 7
+        if (count($proGenAvail) === 0) {
+            $dayNames = ['MONDAY', 'TUESDAY', 'WEDNESDAY', 'THURSDAY', 'FRIDAY'];
+            foreach ($dayNames as $dayName) {
+                $item = new \stdClass();
+                $item->day_of_week = $dayName;
+                $item->timezone = $_timezone;
+                $item->start_time = '09:00:00';
+                $item->end_time = '18:00:00';
+                $proGenAvail->push($item);
+            }
+        }
+
+        // create timeline
+        $phpTZ = appTZtoPHPTZ($_timezone);
+        $phpTZObject = new \DateTimeZone($phpTZ);
+        $startDate = new \DateTime($_start, $phpTZObject);
+        $endDate = new \DateTime($_end, $phpTZObject);
+        $proTimeLine = new TimeLine($startDate, $endDate);
+
+        // General availability
+        $period = new \DatePeriod($startDate, \DateInterval::createFromDateString('1 day'), $endDate);
+        $days = [];
+        foreach ($period as $day) {
+            $days[] = [
+                "day" => strtoupper($day->format("l")), // SUNDAY, etc.
+                "date" => $day->format("Y-m-d"), // 2020-10-04, etc.
+            ];
+        }
+        foreach ($days as $day) {
+            $proGenAvailForTheDay = $proGenAvail->filter(function ($record) use ($day) {
+                return $record->day_of_week === $day["day"];
+            });
+            foreach ($proGenAvailForTheDay as $ga) {
+                $gaStart = new \DateTime($day["date"], new \DateTimeZone(appTZtoPHPTZ($ga->timezone)));
+                $parts = explode(":", $ga->start_time);
+                $gaStart->setTime(intval($parts[0]), intval($parts[1]), intval($parts[2]));
+                $gaStart->setTimezone($phpTZObject);
+                $gaEnd = new \DateTime($day["date"], new \DateTimeZone(appTZtoPHPTZ($ga->timezone)));
+                $parts = explode(":", $ga->end_time);
+                $gaEnd->setTime(intval($parts[0]), intval($parts[1]), intval($parts[2]));
+                $gaEnd->setTimezone($phpTZObject);
+                $proTimeLine->addAvailability($gaStart, $gaEnd);
+            }
+        }
+
+        // specific availability
+        foreach ($proSpecAvail as $sa) {
+            $saStart = new \DateTime($sa->start_time, new \DateTimeZone(appTZtoPHPTZ($sa->timezone)));
+            $saStart->setTimezone($phpTZObject);
+            $saEnd = new \DateTime($sa->end_time, new \DateTimeZone(appTZtoPHPTZ($sa->timezone)));
+            $saEnd->setTimezone($phpTZObject);
+            $proTimeLine->addAvailability($saStart, $saEnd);
+        }
+
+        // specific unavailability
+        foreach ($proSpecUnavail as $sua) {
+            $suaStart = new \DateTime($sua->start_time, new \DateTimeZone(appTZtoPHPTZ($sua->timezone)));
+            $suaStart->setTimezone($phpTZObject);
+            $suaEnd = new \DateTime($sua->end_time, new \DateTimeZone(appTZtoPHPTZ($sua->timezone)));
+            $suaEnd->setTimezone($phpTZObject);
+            $proTimeLine->removeAvailability($suaStart, $suaEnd);
+        }
+
+        $events = [];
+
+        // availability
+        foreach ($proTimeLine->getAvailable() as $item) {
+            $eStart = new \DateTime('@' . $item->start);
+            $eStart->setTimezone($phpTZObject);
+            $eEnd = new \DateTime('@' . $item->end);
+            $eEnd->setTimezone($phpTZObject);
+            $events[] = [
+                "type" => "availability",
+                "start" => $eStart->format('Y-m-d H:i:s'),
+                "end" => $eEnd->format('Y-m-d H:i:s'),
+                "editable" => false,
+                "backgroundColor" => $_availableBG
+            ];
+        }
+
+        // unavailability
+        foreach ($proTimeLine->getUnavailable() as $item) {
+            $eStart = new \DateTime('@' . $item->start);
+            $eStart->setTimezone($phpTZObject);
+            $eEnd = new \DateTime('@' . $item->end);
+            $eEnd->setTimezone($phpTZObject);
+            $events[] = [
+                "type" => "unavailability",
+                "start" => $eStart->format('Y-m-d H:i:s'),
+                "end" => $eEnd->format('Y-m-d H:i:s'),
+                "editable" => false,
+                "backgroundColor" => $_unavailableBG
+            ];
+        }
+
+        return $events;
+
+
+    }
 }