reviewed epic 3
This commit is contained in:
@@ -73,6 +73,7 @@ Schema::create('blocked_times', function (Blueprint $table) {
|
||||
|
||||
namespace App\Models;
|
||||
|
||||
use Carbon\Carbon;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
|
||||
class BlockedTime extends Model
|
||||
@@ -128,6 +129,7 @@ class BlockedTime extends Model
|
||||
```php
|
||||
<?php
|
||||
|
||||
use App\Models\AdminLog;
|
||||
use App\Models\BlockedTime;
|
||||
use Livewire\Volt\Component;
|
||||
|
||||
@@ -210,6 +212,24 @@ new class extends Component {
|
||||
};
|
||||
```
|
||||
|
||||
### Pending Booking Warning Check
|
||||
```php
|
||||
// Add to Volt component - check for pending bookings before save
|
||||
public function checkPendingBookings(): array
|
||||
{
|
||||
$date = Carbon::parse($this->block_date);
|
||||
|
||||
return Consultation::where('scheduled_date', $date->toDateString())
|
||||
->where('status', 'pending')
|
||||
->when(!$this->is_all_day, function ($query) {
|
||||
$query->whereBetween('scheduled_time', [$this->start_time, $this->end_time]);
|
||||
})
|
||||
->with('user:id,full_name,company_name')
|
||||
->get()
|
||||
->toArray();
|
||||
}
|
||||
```
|
||||
|
||||
### Integration with Availability Service
|
||||
```php
|
||||
// In AvailabilityService
|
||||
@@ -296,6 +316,73 @@ public function isDateFullyBlocked(Carbon $date): bool
|
||||
</div>
|
||||
```
|
||||
|
||||
## Assumptions
|
||||
|
||||
- `AdminLog` model exists from Epic 1 with fields: `admin_id`, `action_type`, `target_type`, `target_id`, `new_values`, `ip_address`
|
||||
- Route naming convention: `admin.blocked-times.{index|create|edit}`
|
||||
- Admin middleware protecting all blocked-times routes
|
||||
- Flux UI modal component available for delete confirmation
|
||||
|
||||
## Required Translation Keys
|
||||
|
||||
```php
|
||||
// lang/en/*.php and lang/ar/*.php
|
||||
'messages.blocked_time_saved' => 'Blocked time saved successfully',
|
||||
'messages.blocked_time_deleted' => 'Blocked time deleted successfully',
|
||||
'admin.blocked_times' => 'Blocked Times',
|
||||
'admin.add_blocked_time' => 'Add Blocked Time',
|
||||
'admin.all_day' => 'All Day',
|
||||
'admin.closed' => 'Closed',
|
||||
'admin.no_blocked_times' => 'No blocked times found',
|
||||
'common.edit' => 'Edit',
|
||||
'common.delete' => 'Delete',
|
||||
'common.to' => 'to',
|
||||
```
|
||||
|
||||
## Test Scenarios
|
||||
|
||||
### Feature Tests (`tests/Feature/BlockedTimeTest.php`)
|
||||
|
||||
**CRUD Operations:**
|
||||
- [ ] Admin can create an all-day block
|
||||
- [ ] Admin can create a time-range block (e.g., 09:00-12:00)
|
||||
- [ ] Admin can add optional reason to blocked time
|
||||
- [ ] Admin can edit an existing blocked time
|
||||
- [ ] Admin can delete a blocked time
|
||||
- [ ] Non-admin users cannot access blocked time routes
|
||||
|
||||
**Validation:**
|
||||
- [ ] Cannot create block with end_time before start_time
|
||||
- [ ] Cannot create block for past dates (new blocks only)
|
||||
- [ ] Can edit existing blocks for past dates (data integrity)
|
||||
- [ ] Reason field respects 255 character max length
|
||||
|
||||
**List View:**
|
||||
- [ ] List displays all blocked times sorted by date (upcoming first)
|
||||
- [ ] Filter by "upcoming" shows only future blocks
|
||||
- [ ] Filter by "past" shows only past blocks
|
||||
- [ ] Filter by "all" shows all blocks
|
||||
|
||||
**Integration:**
|
||||
- [ ] `blocksSlot()` returns true for times within blocked range
|
||||
- [ ] `blocksSlot()` returns true for all times when all-day block
|
||||
- [ ] `blocksSlot()` returns false for times outside blocked range
|
||||
- [ ] `isDateFullyBlocked()` correctly identifies all-day blocks
|
||||
- [ ] `getBlockedSlots()` returns correct slots for partial day blocks
|
||||
|
||||
**Edge Cases:**
|
||||
- [ ] Multiple blocks on same date handled correctly
|
||||
- [ ] Block at end of working hours (edge of range)
|
||||
- [ ] Warning displayed when blocking date with pending consultations
|
||||
|
||||
### Unit Tests (`tests/Unit/BlockedTimeTest.php`)
|
||||
|
||||
- [ ] `isAllDay()` returns true when start_time and end_time are null
|
||||
- [ ] `isAllDay()` returns false when times are set
|
||||
- [ ] `scopeUpcoming()` filters correctly
|
||||
- [ ] `scopePast()` filters correctly
|
||||
- [ ] `scopeForDate()` filters by exact date
|
||||
|
||||
## Definition of Done
|
||||
|
||||
- [ ] Can create all-day blocks
|
||||
@@ -313,8 +400,12 @@ public function isDateFullyBlocked(Carbon $date): bool
|
||||
|
||||
## Dependencies
|
||||
|
||||
- **Story 3.1:** Working hours configuration
|
||||
- **Story 3.3:** Availability calendar (consumes blocked times)
|
||||
- **Story 3.1:** Working hours configuration (`docs/stories/story-3.1-working-hours-configuration.md`)
|
||||
- Provides: `WorkingHour` model, `AvailabilityService` base
|
||||
- **Story 3.3:** Availability calendar (`docs/stories/story-3.3-availability-calendar-display.md`)
|
||||
- Consumes: blocked times data for calendar display
|
||||
- **Epic 1:** Core Foundation
|
||||
- Provides: `AdminLog` model for audit logging, admin authentication
|
||||
|
||||
## Risk Assessment
|
||||
|
||||
|
||||
Reference in New Issue
Block a user