coursework tasks 1 to 10
This commit is contained in:
169
app/Http/Controllers/AvailabilitiesController.php
Normal file
169
app/Http/Controllers/AvailabilitiesController.php
Normal file
@@ -0,0 +1,169 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers;
|
||||
|
||||
use App\Models\EmployeeAvailability;
|
||||
use App\Models\User;
|
||||
use Illuminate\Http\Request;
|
||||
|
||||
class AvailabilitiesController extends Controller
|
||||
{
|
||||
// GET api/admin/availabilities?employee_id=5&date=2025-06-15
|
||||
public function index(Request $request)
|
||||
{
|
||||
$query = EmployeeAvailability::query();
|
||||
|
||||
if ($request->employee_id) {
|
||||
$query->where('employee_id', $request->employee_id);
|
||||
}
|
||||
if ($request->date) {
|
||||
$query->where('date', $request->date);
|
||||
}
|
||||
|
||||
$availabilities = $query->get();
|
||||
return response()->json($availabilities);
|
||||
}
|
||||
|
||||
// POST api/admin/availabilities - создать один слот
|
||||
public function store(Request $request)
|
||||
{
|
||||
$request->validate([
|
||||
'employee_id' => 'required|exists:users,id',
|
||||
'date' => 'required|date',
|
||||
'starttime' => 'required',
|
||||
'endtime' => 'required|after:starttime',
|
||||
'isavailable' => 'boolean'
|
||||
]);
|
||||
|
||||
$availability = EmployeeAvailability::create($request->all());
|
||||
return response()->json($availability, 201);
|
||||
}
|
||||
|
||||
// POST api/admin/availabilities/bulk - создать несколько слотов
|
||||
public function bulkStore(Request $request)
|
||||
{
|
||||
$request->validate([
|
||||
'employee_id' => 'required|exists:users,id',
|
||||
'date' => 'required|date',
|
||||
'intervals' => 'required|array|min:1'
|
||||
]);
|
||||
|
||||
$availabilities = [];
|
||||
foreach ($request->intervals as $interval) {
|
||||
$availability = EmployeeAvailability::create([
|
||||
'employee_id' => $request->employee_id,
|
||||
'date' => $request->date,
|
||||
'starttime' => $interval['start'],
|
||||
'endtime' => $interval['end'],
|
||||
'isavailable' => true
|
||||
]);
|
||||
$availabilities[] = $availability;
|
||||
}
|
||||
|
||||
return response()->json($availabilities, 201);
|
||||
}
|
||||
|
||||
// DELETE api/admin/availabilities/{id} - удалить слот (брони остаются!)
|
||||
public function destroy($id)
|
||||
{
|
||||
$availability = EmployeeAvailability::findOrFail($id);
|
||||
$availability->delete();
|
||||
|
||||
return response()->json(['message' => 'Слот удален из расписания (брони сохранены)']);
|
||||
}
|
||||
public function publicAvailability(Request $request)
|
||||
{
|
||||
$serviceId = $request->query('service_id');
|
||||
$date = $request->query('date');
|
||||
|
||||
if (!$serviceId || !$date) {
|
||||
return response()->json(['error' => 'service_id и date обязательны'], 400);
|
||||
}
|
||||
|
||||
// Найти услугу и получить длительность
|
||||
$service = \App\Models\Services::find($serviceId);
|
||||
if (!$service) {
|
||||
return response()->json(['error' => 'Услуга не найдена'], 404);
|
||||
}
|
||||
|
||||
$durationMinutes = $service->durationminutes;
|
||||
|
||||
// Найти сотрудников с расписанием на эту дату
|
||||
$availabilities = \App\Models\EmployeeAvailability::where('date', $date)
|
||||
->where('isavailable', true)
|
||||
->with('employee') // связь с User
|
||||
->get();
|
||||
|
||||
$freeSlots = [];
|
||||
|
||||
foreach ($availabilities as $availability) {
|
||||
$employeeId = $availability->employee_id;
|
||||
|
||||
// Найти занятые слоты этого сотрудника
|
||||
$bookings = \App\Models\Booking::where('employee_id', $employeeId)
|
||||
->where('bookingdate', $date)
|
||||
->where('status', '!=', 'cancelled')
|
||||
->pluck('starttime', 'endtime');
|
||||
|
||||
// Генерировать возможные слоты с учетом duration
|
||||
$start = new \DateTime($availability->starttime);
|
||||
$end = new \DateTime($availability->endtime);
|
||||
|
||||
$current = clone $start;
|
||||
while ($current < $end) {
|
||||
$slotEnd = clone $current;
|
||||
$slotEnd->modify("+{$durationMinutes} minutes");
|
||||
|
||||
// Проверить пересечение с бронями
|
||||
$isFree = true;
|
||||
foreach ($bookings as $bookingStart => $bookingEnd) {
|
||||
$bookingStartTime = new \DateTime($bookingStart);
|
||||
$bookingEndTime = new \DateTime($bookingEnd);
|
||||
|
||||
if ($current < $bookingEndTime && $slotEnd > $bookingStartTime) {
|
||||
$isFree = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if ($isFree && $slotEnd <= $end) {
|
||||
$freeSlots[] = [
|
||||
'employee_id' => $employeeId,
|
||||
'start' => $current->format('H:i'),
|
||||
'end' => $slotEnd->format('H:i')
|
||||
];
|
||||
}
|
||||
|
||||
$current->modify('+30 minutes'); // шаг 30 мин
|
||||
}
|
||||
}
|
||||
|
||||
return response()->json($freeSlots);
|
||||
}
|
||||
public function cancel(Request $request, $id)
|
||||
{
|
||||
$booking = Booking::findOrFail($id);
|
||||
|
||||
// Проверка: только автор брони может отменить
|
||||
if ($booking->client_id != auth()->id()) {
|
||||
return response()->json(['error' => 'Можете отменить только свою бронь'], 403);
|
||||
}
|
||||
|
||||
// Проверка: нельзя отменить уже отмененную/выполненную
|
||||
if ($booking->status != 'confirmed') {
|
||||
return response()->json(['error' => 'Можно отменить только подтвержденные брони'], 400);
|
||||
}
|
||||
|
||||
// Обновить статус
|
||||
$booking->update([
|
||||
'status' => 'cancelled',
|
||||
'cancelledby' => 'client',
|
||||
'cancelreason' => $request->reason ?? null
|
||||
]);
|
||||
|
||||
return response()->json([
|
||||
'message' => 'Бронь отменена',
|
||||
'booking' => $booking
|
||||
]);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user