timegridio/concierge

View on GitHub
src/Vacancy/VacancyManager.php

Summary

Maintainability
A
1 hr
Test Coverage
<?php

namespace Timegridio\Concierge\Vacancy;

use Carbon\Carbon;
use Timegridio\Concierge\Models\Business;
use Timegridio\Concierge\Models\Vacancy;

class VacancyManager
{
    protected $business;

    protected $builder;

    public function __construct(Business $business)
    {
        $this->business = $business;
    }

    public function builder()
    {
        if ($this->builder === null) {
            $this->builder = new VacancyTemplateBuilder();
        }

        return $this->builder;
    }

    /**
     * Update vacancies from batch statements.
     *
     * @param Business $business
     * @param array    $parsedStatements
     *
     * @return bool
     */
    public function updateBatch(Business $business, $parsedStatements)
    {
        $changed = false;
        $dates = $this->arrayGroupBy('date', $parsedStatements);

        foreach ($dates as $date => $statements) {
            $services = $this->arrayGroupBy('service', $statements);

            $changed |= $this->processServiceStatements($business, $date, $services);
        }

        return $changed;
    }

    public function unpublish()
    {
        return $this->business->vacancies()->delete();
    }

    protected function processServiceStatements($business, $date, $services)
    {
        $changed = false;
        foreach ($services as $serviceSlug => $statements) {
            $service = $business->services()->where('slug', $serviceSlug)->get()->first();

            if ($service === null) {

                //  Invalid services are skipped to avoid user frustration.
                //  TODO: Still, a user-level WARNING should be raised with no fatal error

                continue;
            }

            $vacancy = $business->vacancies()->forDate(Carbon::parse($date))->forService($service->id);

            if ($vacancy) {
                $vacancy->delete();
            }

            $changed |= $this->processStatements($business, $date, $service, $statements);
        }

        return $changed;
    }

    protected function processStatements($business, $date, $service, $statements)
    {
        $changed = false;
        foreach ($statements as $statement) {
            $changed |= $this->publishVacancy($business, $date, $service, $statement);
        }

        return $changed;
    }

    protected function publishVacancy($business, $date, $service, $statement)
    {
        $date = $statement['date'];
        $startAt = $statement['startAt'];
        $finishAt = $statement['finishAt'];

        $startAt = Carbon::parse("{$date} {$startAt} {$business->timezone}")->timezone('UTC');
        $finishAt = Carbon::parse("{$date} {$finishAt} {$business->timezone}")->timezone('UTC');

        $vacancyValues = [
            'business_id' => $business->id,
            'service_id'  => $service->id,
            'date'        => $statement['date'],
            'start_at'    => $startAt,
            'finish_at'   => $finishAt,
            ];

        // If capacity is a slug, grab the humanresource
        if(!is_numeric($statement['capacity']))
        {
            $vacancyValues['humanresource_id'] = $business->humanresources()
                                                          ->where('slug', $statement['capacity'])
                                                          ->first()
                                                          ->id;
        }
        else
        {
            $vacancyValues['capacity'] = intval($statement['capacity']);
        }

        $vacancy = Vacancy::create($vacancyValues);

        return $vacancy !== null;
    }

    protected function arrayGroupBy($key, $array)
    {
        $grouped = [];
        foreach ($array as $hash => $item) {
            if (!array_key_exists($item[$key], $grouped)) {
                $grouped[$item[$key]] = [];
            }
            $grouped[$item[$key]][] = $item;
        }

        return $grouped;
    }

    public function publish($date, Carbon $startAt, Carbon $finishAt, $serviceId, $capacity = 1)
    {
        $vacancyKeys = [
            'business_id' => $this->business->id,
            'service_id'  => $serviceId,
            'date'        => $date,
            ];
        $vacancyValues = [
            'capacity'    => intval($capacity),
            'start_at'    => $startAt->timezone('UTC')->toDateTimeString(),
            'finish_at'   => $finishAt->timezone('UTC')->toDateTimeString(),
            ];

        return Vacancy::updateOrCreate($vacancyKeys, $vacancyValues);
    }

    /**
     * [generateAvailability description].
     *
     * @param Illuminate\Database\Eloquent\Collection $vacancies
     * @param string                                  $startDate
     * @param int                                     $futureDays
     *
     * @return array
     */
    public function generateAvailability($startDate = 'today', $futureDays = 10)
    {
        $dates = [];
        for ($i = 0; $i < $futureDays; $i++) {
            $dates[date('Y-m-d', strtotime("$startDate +$i days"))] = [];
        }

        foreach ($this->business->vacancies as $vacancy) {
            if (array_key_exists($vacancy->date, $dates)) {
                $dates[$vacancy->date][$vacancy->service->slug] = $vacancy;
            }
        }

        return $dates;
    }
}