Files
cleaning-company/app/Http/Controllers/AvailabilitiesController.php
2026-01-07 11:55:53 +00:00

169 lines
5.9 KiB
PHP
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<?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
]);
}
}