2025-10-13 14:57:11 +02:00
|
|
|
<?php
|
|
|
|
|
|
|
|
|
|
namespace Tests\Feature\Schedule;
|
|
|
|
|
|
|
|
|
|
use App\Models\Dish;
|
|
|
|
|
use App\Models\Planner;
|
|
|
|
|
use App\Models\UserDish;
|
|
|
|
|
use App\Models\UserDishRecurrence;
|
|
|
|
|
use App\Models\Schedule;
|
|
|
|
|
use App\Models\ScheduledUserDish;
|
|
|
|
|
use App\Models\User;
|
|
|
|
|
use App\Models\WeeklyRecurrence;
|
|
|
|
|
use Illuminate\Foundation\Testing\RefreshDatabase;
|
|
|
|
|
use Illuminate\Support\Carbon;
|
|
|
|
|
use Illuminate\Testing\Fluent\AssertableJson;
|
|
|
|
|
use Tests\TestCase;
|
|
|
|
|
use Tests\Traits\HasPlanner;
|
|
|
|
|
|
|
|
|
|
class GenerateScheduleTest extends TestCase
|
|
|
|
|
{
|
|
|
|
|
use HasPlanner;
|
|
|
|
|
use RefreshDatabase;
|
|
|
|
|
|
2025-12-29 23:36:15 +01:00
|
|
|
protected function setUp(): void
|
|
|
|
|
{
|
|
|
|
|
parent::setUp();
|
|
|
|
|
$this->setUpHasPlanner();
|
|
|
|
|
}
|
|
|
|
|
|
2025-10-13 14:57:11 +02:00
|
|
|
public function test_user_can_generate_schedule(): void
|
|
|
|
|
{
|
|
|
|
|
$planner = $this->planner;
|
|
|
|
|
$users = User::factory()->planner($planner)->count(2)->create(); // Create users
|
|
|
|
|
$dishes = Dish::factory()->planner($planner)->count(200)->create(); // Create dishes
|
|
|
|
|
|
|
|
|
|
// Attach dishes to users, ensuring `UserDish` records exist for every user
|
|
|
|
|
$users->each(function (User $user) use ($dishes) {
|
|
|
|
|
$dishes->random(50)->each(function (Dish $dish) use ($user) {
|
|
|
|
|
UserDish::factory()->create([
|
|
|
|
|
'user_id' => $user->id,
|
|
|
|
|
'dish_id' => $dish->id,
|
|
|
|
|
]);
|
|
|
|
|
});
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
$this->assertDatabaseEmpty(Schedule::class);
|
|
|
|
|
|
|
|
|
|
$this
|
|
|
|
|
->actingAs($planner)
|
|
|
|
|
->post(route('api.schedule.generate'))
|
|
|
|
|
->assertStatus(200)
|
|
|
|
|
->assertJson(fn (AssertableJson $json) => $json
|
|
|
|
|
->where('success', true)
|
|
|
|
|
->where('payload', null)
|
|
|
|
|
->where('errors', null)
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
$this->assertDatabaseCount(Schedule::class, 14);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public function test_fresh_schedule_adheres_to_fixed_recurrences(): void
|
|
|
|
|
{
|
|
|
|
|
$planner = $this->planner;
|
|
|
|
|
$targetDate = now()->addDay();
|
|
|
|
|
$users = User::factory()->planner($planner)->count(2)->create(); // Create users
|
|
|
|
|
$dishes = Dish::factory()->planner($planner)->count(200)->create(); // Create dishes
|
|
|
|
|
|
|
|
|
|
// Attach dishes to users, ensuring `UserDish` records exist for every user
|
|
|
|
|
$users->each(function (User $user) use ($dishes) {
|
|
|
|
|
$dishes->random(50)->each(function (Dish $dish) use ($user) {
|
|
|
|
|
UserDish::factory()->create([
|
|
|
|
|
'user_id' => $user->id,
|
|
|
|
|
'dish_id' => $dish->id,
|
|
|
|
|
]);
|
|
|
|
|
});
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
$targetUserDish = UserDish::query()
|
|
|
|
|
->whereNotNull('dish_id')
|
|
|
|
|
->whereNotNull('user_id')
|
|
|
|
|
->get()
|
|
|
|
|
->random();
|
|
|
|
|
|
|
|
|
|
$weeklyRecurrence = WeeklyRecurrence::factory()->create([
|
|
|
|
|
'weekday' => $targetDate->dayOfWeek(),
|
|
|
|
|
]);
|
|
|
|
|
|
|
|
|
|
$fixedRecurrence = UserDishRecurrence::factory()->create([
|
|
|
|
|
'user_dish_id' => $targetUserDish->id,
|
|
|
|
|
'recurrence_id' => $weeklyRecurrence->id,
|
|
|
|
|
'recurrence_type' => $weeklyRecurrence::class,
|
|
|
|
|
]);
|
|
|
|
|
|
|
|
|
|
$this->assertDatabaseEmpty(Schedule::class);
|
|
|
|
|
|
|
|
|
|
$this
|
|
|
|
|
->actingAs($planner)
|
|
|
|
|
->post(route('api.schedule.generate'))
|
|
|
|
|
->assertStatus(200)
|
|
|
|
|
->assertJson(fn (AssertableJson $json) => $json
|
|
|
|
|
->where('success', true)
|
|
|
|
|
->where('payload', null)
|
|
|
|
|
->where('errors', null)
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
$this->assertDatabaseCount(Schedule::class, 14);
|
|
|
|
|
$targetDateSchedule = Schedule::query()->where('date', $targetDate->format('Y-m-d'))->first();
|
|
|
|
|
|
|
|
|
|
$this->assertNotNull($targetDateSchedule);
|
|
|
|
|
|
|
|
|
|
$targetScheduledUserDishes = $targetDateSchedule
|
|
|
|
|
->scheduledUserDishes
|
|
|
|
|
->pluck('user_dish_id')
|
|
|
|
|
->toArray();
|
|
|
|
|
|
|
|
|
|
$this->assertContains($targetUserDish->id, $targetScheduledUserDishes);
|
|
|
|
|
}
|
|
|
|
|
public function test_schedule_can_be_overwritten(): void
|
|
|
|
|
{
|
|
|
|
|
$planner = $this->planner;
|
|
|
|
|
$users = User::factory()->planner($planner)->count(2)->create(); // Create users
|
|
|
|
|
$dishes = Dish::factory()->planner($planner)->count(200)->create(); // Create dishes
|
|
|
|
|
|
|
|
|
|
// Attach dishes to users, ensuring `UserDish` records exist for every user
|
|
|
|
|
$users->each(function (User $user) use ($dishes) {
|
|
|
|
|
$dishes->random(50)->each(function (Dish $dish) use ($user) {
|
|
|
|
|
UserDish::factory()->create([
|
|
|
|
|
'user_id' => $user->id,
|
|
|
|
|
'dish_id' => $dish->id,
|
|
|
|
|
]);
|
|
|
|
|
});
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
// Assert that every user has `UserDish` records
|
|
|
|
|
$users->each(fn (User $user) =>
|
|
|
|
|
$this->assertNotEmpty($user->refresh()->userDishes)
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
$scheduleDay = Schedule::factory()
|
|
|
|
|
->planner($planner)
|
|
|
|
|
->create([
|
|
|
|
|
'date' => Carbon::now()->addDay(),
|
|
|
|
|
]);
|
|
|
|
|
|
|
|
|
|
$users->each(fn (User $user) => ScheduledUserDish::factory()
|
|
|
|
|
->create([
|
|
|
|
|
'user_dish_id' => $user->userDishes->random()->id,
|
|
|
|
|
'schedule_id' => $scheduleDay->id,
|
|
|
|
|
'user_id' => $user->id,
|
|
|
|
|
])
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
$scheduleDay->refresh();
|
|
|
|
|
$originalUserDishes = $scheduleDay->scheduledUserDishes->map(fn (ScheduledUserDish $scheduledUserDish) => [
|
|
|
|
|
'user_dish_id' => $scheduledUserDish->user_dish_id,
|
|
|
|
|
]);
|
|
|
|
|
|
|
|
|
|
$this->assertDatabaseCount(Schedule::class, 1);
|
|
|
|
|
$this->assertDatabaseCount(ScheduledUserDish::class, 2);
|
|
|
|
|
|
|
|
|
|
$this
|
|
|
|
|
->actingAs($planner)
|
|
|
|
|
->post(route('api.schedule.generate'), [
|
|
|
|
|
'overwrite' => true,
|
|
|
|
|
])
|
|
|
|
|
->assertStatus(200)
|
|
|
|
|
->assertJson(fn (AssertableJson $json) => $json
|
|
|
|
|
->where('success', true)
|
|
|
|
|
->where('payload', null)
|
|
|
|
|
->where('errors', null)
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
$this->assertDatabaseCount(Schedule::class, 14);
|
|
|
|
|
|
|
|
|
|
$freshScheduleDay = Schedule::query()->where('date', $scheduleDay->date)->first();
|
|
|
|
|
$this->assertNotEquals(
|
|
|
|
|
$originalUserDishes,
|
|
|
|
|
$freshScheduleDay->scheduledUserDishes->map(fn (ScheduledUserDish $scheduledUserDish) => [
|
|
|
|
|
'user_dish_id' => $scheduledUserDish->user_dish_id,
|
|
|
|
|
])
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public function test_fixed_recurrence_takes_precedence_during_overwrite(): void
|
|
|
|
|
{
|
|
|
|
|
$targetDate = now()->addDay();
|
|
|
|
|
$planner = $this->planner;
|
|
|
|
|
$users = User::factory()->planner($planner)->count(2)->create(); // Create users
|
|
|
|
|
$dishes = Dish::factory()->planner($planner)->count(200)->create(); // Create dishes
|
|
|
|
|
|
|
|
|
|
// Attach dishes to users, ensuring `UserDish` records exist for every user
|
|
|
|
|
$users->each(function (User $user) use ($dishes) {
|
|
|
|
|
$dishes->random(50)->each(function (Dish $dish) use ($user) {
|
|
|
|
|
UserDish::factory()->create([
|
|
|
|
|
'user_id' => $user->id,
|
|
|
|
|
'dish_id' => $dish->id,
|
|
|
|
|
]);
|
|
|
|
|
});
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
$scheduleDay = Schedule::factory()
|
|
|
|
|
->planner($planner)
|
|
|
|
|
->date($targetDate)
|
|
|
|
|
->create();
|
|
|
|
|
|
|
|
|
|
$fixedUser = $users->pop();
|
|
|
|
|
$targetUserDish = $fixedUser->userDishes->random();
|
|
|
|
|
|
|
|
|
|
$weeklyRecurrence = WeeklyRecurrence::factory()->create([
|
|
|
|
|
'weekday' => $targetDate->dayOfWeek,
|
|
|
|
|
]);
|
|
|
|
|
|
|
|
|
|
UserDishRecurrence::factory()->create([
|
|
|
|
|
'user_dish_id' => $targetUserDish->id,
|
|
|
|
|
'recurrence_id' => $weeklyRecurrence->id,
|
|
|
|
|
'recurrence_type' => $weeklyRecurrence::class,
|
|
|
|
|
]);
|
|
|
|
|
|
|
|
|
|
$users
|
|
|
|
|
->map(fn (User $user) => ScheduledUserDish::factory()
|
|
|
|
|
->create([
|
|
|
|
|
'schedule_id' => $scheduleDay->id,
|
|
|
|
|
'user_dish_id' => $user->userDishes->random()->id,
|
|
|
|
|
'user_id' => $user->id,
|
|
|
|
|
]));
|
|
|
|
|
|
|
|
|
|
ScheduledUserDish::factory()
|
|
|
|
|
->schedule($scheduleDay)
|
|
|
|
|
->userDish($targetUserDish)
|
|
|
|
|
->create();
|
|
|
|
|
|
|
|
|
|
$scheduleDay->refresh();
|
|
|
|
|
|
|
|
|
|
// assert all days have been filled
|
|
|
|
|
$this->assertDatabaseCount(Schedule::class, 1);
|
|
|
|
|
$this->assertDatabaseCount(ScheduledUserDish::class, 2);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
$this
|
|
|
|
|
->actingAs($planner)
|
|
|
|
|
->post(route('api.schedule.generate'), [
|
|
|
|
|
'overwrite' => true,
|
|
|
|
|
])
|
|
|
|
|
->assertStatus(200)
|
|
|
|
|
->assertJson(fn (AssertableJson $json) => $json
|
|
|
|
|
->where('success', true)
|
|
|
|
|
->where('payload', null)
|
|
|
|
|
->where('errors', null)
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
$this->assertDatabaseCount(Schedule::class, 14);
|
|
|
|
|
|
|
|
|
|
$targetDateSchedule = Schedule::query()->where('date', $targetDate->format('Y-m-d'))->first();
|
|
|
|
|
$this->assertNotNull($targetDateSchedule);
|
|
|
|
|
|
|
|
|
|
$targetScheduledUserDishes = $targetDateSchedule
|
|
|
|
|
->scheduledUserDishes
|
|
|
|
|
->filter(fn (ScheduledUserDish $scheduledUserDish) => $scheduledUserDish->userDish->user->id === $fixedUser->id);
|
|
|
|
|
|
|
|
|
|
$this->assertCount(1, $targetScheduledUserDishes);
|
|
|
|
|
$this->assertContains($targetUserDish->id, $targetScheduledUserDishes->pluck('user_dish_id')->toArray());
|
|
|
|
|
}
|
|
|
|
|
}
|