Check start/end/days of week in cron and active/deactivate flights accordingly

This commit is contained in:
Nabeel Shahzad 2018-04-12 16:12:32 -05:00
parent 395642f69c
commit 9d3d284df7
6 changed files with 224 additions and 6 deletions

View File

@ -0,0 +1,70 @@
<?php
namespace App\Cron\Nightly;
use App\Events\CronNightly;
use App\Interfaces\Listener;
use App\Models\Enums\Days;
use App\Models\Flight;
use Carbon\Carbon;
/**
* Figure out what flights need to be active for today
* @package App\Cron\Nightly
*/
class SetActiveFlights extends Listener
{
/**
* @param CronNightly $event
*/
public function handle(CronNightly $event): void
{
$this->checkFlights();
}
/**
* Look through every single flight, check the start/end dates,
* as well of the days of week if this flight is active on this day
*
* TODO: Option to check the flight active/inactive against departure TZ
* TODO: Move to FlightService
*/
public function checkFlights(): void
{
$today = Carbon::now('UTC');
$flights = Flight::all();
/**
* @var Flight $flight
*/
foreach($flights as $flight) {
// dates aren't set, so just save if there were any changes above
// and move onto the next one
if ($flight->start_date === null || $flight->end_date === null) {
if ($flight->days > 0) {
$flight->active = Days::isToday($flight->days);
}
$flight->save();
continue;
}
// Check the day of week now first
// Start/end date is set, so make sure today is valid for it to be alive
// and then make sure if days of the week are specified, check that too
if ($today->gte($flight->start_date) && $today->lte($flight->end_date)) {
if ($flight->days > 0) {
$flight->active = Days::isToday($flight->days);
} else {
$flight->active = true;
}
} else {
$flight->active = false;
}
$flight->save();
}
}
}

View File

@ -1,12 +1,11 @@
<?php
/**
* Create flights
*/
use Faker\Generator as Faker;
# Match the list available in tests/data/*.yml
$airlinesAvailable = [1];
$factory->define(App\Models\Flight::class, function (Faker $faker) use ($airlinesAvailable) {
$factory->define(App\Models\Flight::class, function (Faker $faker) {
return [
'id' => null,
'airline_id' => function () {
@ -26,13 +25,15 @@ $factory->define(App\Models\Flight::class, function (Faker $faker) use ($airline
},
'distance' => $faker->numberBetween(0, 3000),
'route' => null,
'days' => 0,
'level' => 0,
'dpt_time' => $faker->time(),
'arr_time' => $faker->time(),
'flight_time' => $faker->numberBetween(60, 360),
'has_bid' => false,
'active' => true,
'days' => 0,
'start_date' => null,
'end_date' => null,
'created_at' => $faker->dateTimeBetween('-1 week', 'now'),
'updated_at' => function (array $flight) {
return $flight['created_at'];

View File

@ -39,6 +39,19 @@ class Days extends Enum
'Su' => Days::SUNDAY,
];
/**
* Map the ISO8601 numeric today to day
*/
public static $isoDayMap = [
1 => Days::MONDAY,
2 => Days::TUESDAY,
3 => Days::WEDNESDAY,
4 => Days::THURSDAY,
5 => Days::FRIDAY,
6 => Days::SATURDAY,
7 => Days::SUNDAY,
];
/**
* Create the masked value for the days of week
* @param array $days
@ -64,4 +77,14 @@ class Days extends Enum
{
return ($mask & $day) === $day;
}
/**
* Does the mask contain today?
* @param $val
* @return bool
*/
public static function isToday($val): bool
{
return static::in($val, static::$isoDayMap[(int) date('N')]);
}
}

View File

@ -6,6 +6,7 @@ use App\Interfaces\Model;
use App\Models\Enums\Days;
use App\Models\Traits\HashIdTrait;
use App\Support\Units\Distance;
use Carbon\Carbon;
use Illuminate\Support\Collection;
use PhpUnitsOfMeasure\Exception\NonNumericValue;
use PhpUnitsOfMeasure\Exception\NonStringUnitName;
@ -26,6 +27,9 @@ use PhpUnitsOfMeasure\Exception\NonStringUnitName;
* @property string dpt_airport_id
* @property string arr_airport_id
* @property string alt_airport_id
* @property int active
* @property Carbon start_date
* @property Carbon end_date
*/
class Flight extends Model
{
@ -178,6 +182,20 @@ class Flight extends Model
return '';
}
/**
* Set the days parameter. If an array is passed, it's
* AND'd together to create the mask value
* @param array|int $val
*/
public function setDaysAttribute($val): void
{
if (\is_array($val)) {
$val = Days::getDaysMask($val);
}
$this->attributes['days'] = $val;
}
/**
* Relationship
*/

View File

@ -2,6 +2,7 @@
namespace App\Providers;
use App\Cron\Nightly\SetActiveFlights;
use App\Events\CronMonthly;
use App\Events\CronNightly;
use App\Events\CronWeekly;
@ -29,6 +30,7 @@ class EventServiceProvider extends ServiceProvider
ApplyExpenses::class,
RecalculateBalances::class,
PilotLeave::class,
SetActiveFlights::class,
],
CronWeekly::class => [
@ -42,6 +44,7 @@ class EventServiceProvider extends ServiceProvider
AwardListener::class,
],
];
protected $subscribe = [
FinanceEvents::class,
NotificationEvents::class,

View File

@ -149,6 +149,109 @@ class FlightTest extends TestCase
$flight = Flight::findByDays([Days::WEDNESDAY, Days::THURSDAY])->first();
$this->assertNull($flight);
}
/**
* Make sure that flights are marked as inactive when they're out of the start/end
* zones. also make sure that flights with a specific day of the week are only
* active on those days
*/
public function testDayOfWeekActive(): void
{
$this->user = factory(App\Models\User::class)->create();
// Set it to Monday or Tuesday, depending on what today is
if (date('N') === 1) { // today is a monday
$days = Days::getDaysMask([Days::TUESDAY]);
} else {
$days = Days::getDaysMask([Days::MONDAY]);
}
factory(App\Models\Flight::class, 5)->create();
$flight = factory(App\Models\Flight::class)->create([
'days' => $days,
#'start_date' => Carbon\Carbon::now('UTC')->subDay(1),
#'end_date' => Carbon\Carbon::now('UTC')->addDays(1),
]);
// Run the event that will enable/disable flights
$event = new \App\Events\CronNightly();
(new \App\Cron\Nightly\SetActiveFlights())->handle($event);
$res = $this->get('/api/flights');
$body = $res->json('data');
$flights = collect($body)->where('id', $flight->id)->first();
$this->assertNull($flights);
}
public function testStartEndDate(): void
{
$this->user = factory(App\Models\User::class)->create();
factory(App\Models\Flight::class, 5)->create();
$flight = factory(App\Models\Flight::class)->create([
'start_date' => Carbon\Carbon::now('UTC')->subDays(1),
'end_date' => Carbon\Carbon::now('UTC')->addDays(1),
]);
$flight_not_active = factory(App\Models\Flight::class)->create([
'start_date' => Carbon\Carbon::now('UTC')->subDays(10),
'end_date' => Carbon\Carbon::now('UTC')->subDays(2),
]);
// Run the event that will enable/disable flights
$event = new \App\Events\CronNightly();
(new \App\Cron\Nightly\SetActiveFlights())->handle($event);
$res = $this->get('/api/flights');
$body = $res->json('data');
$flights = collect($body)->where('id', $flight->id)->first();
$this->assertNotNull($flights);
$flights = collect($body)->where('id', $flight_not_active->id)->first();
$this->assertNull($flights);
}
public function testStartEndDateDayOfWeek(): void
{
$this->user = factory(App\Models\User::class)->create();
// Set it to Monday or Tuesday, depending on what today is
if (date('N') === 1) { // today is a monday
$days = Days::getDaysMask([Days::TUESDAY]);
} else {
$days = Days::getDaysMask([Days::MONDAY]);
}
factory(App\Models\Flight::class, 5)->create();
$flight = factory(App\Models\Flight::class)->create([
'start_date' => Carbon\Carbon::now('UTC')->subDays(1),
'end_date' => Carbon\Carbon::now('UTC')->addDays(1),
'days' => Days::$isoDayMap[date('N')],
]);
$flight_not_active = factory(App\Models\Flight::class)->create([
'start_date' => Carbon\Carbon::now('UTC')->subDays(1),
'end_date' => Carbon\Carbon::now('UTC')->addDays(1),
'days' => $days,
]);
// Run the event that will enable/disable flights
$event = new \App\Events\CronNightly();
(new \App\Cron\Nightly\SetActiveFlights())->handle($event);
$res = $this->get('/api/flights');
$body = $res->json('data');
$flights = collect($body)->where('id', $flight->id)->first();
$this->assertNotNull($flights);
$flights = collect($body)->where('id', $flight_not_active->id)->first();
$this->assertNull($flights);
}
/**