commit 12.01
This commit is contained in:
@@ -5,61 +5,31 @@ namespace App\Http\Controllers;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Facades\Auth;
|
||||
use Illuminate\Support\Facades\Validator;
|
||||
use App\Models\User;
|
||||
use Illuminate\Support\Facades\Hash;
|
||||
|
||||
|
||||
class AuthController extends Controller
|
||||
{
|
||||
// Регистрация нового пользователя
|
||||
public function register(Request $request)
|
||||
{
|
||||
$validator = Validator::make($request->all(), [
|
||||
'name' => 'required|string|max:255',
|
||||
'email' => 'required|email|unique:users,email',
|
||||
'password' => 'required|string|min:6',
|
||||
]);
|
||||
|
||||
if ($validator->fails()) {
|
||||
return response()->json([
|
||||
'message' => 'Ошибка валидации',
|
||||
'errors' => $validator->errors()
|
||||
], 422);
|
||||
}
|
||||
|
||||
$user = \App\Models\User::create([
|
||||
'name' => $request->name,
|
||||
'email' => $request->email,
|
||||
'password' => bcrypt($request->password),
|
||||
'phone' => $request->phone ?? null,
|
||||
'role' => 'client', // по умолчанию клиент
|
||||
]);
|
||||
|
||||
// Создаём токен для Sanctum
|
||||
$token = $user->createToken('main-token')->plainTextToken;
|
||||
|
||||
return response()->json([
|
||||
'message' => 'Пользователь создан',
|
||||
'user' => $user,
|
||||
'token' => $token
|
||||
], 201);
|
||||
}
|
||||
|
||||
// Вход
|
||||
public function login(Request $request)
|
||||
{
|
||||
$credentials = $request->only('email', 'password');
|
||||
{
|
||||
$request->validate([
|
||||
'email' => 'required|email',
|
||||
'password' => 'required'
|
||||
]);
|
||||
|
||||
if (!Auth::attempt($credentials)) {
|
||||
return response()->json([
|
||||
'message' => 'Неверный email или пароль'
|
||||
], 401);
|
||||
}
|
||||
$user = \App\Models\User::where('email', $request->email)->first();
|
||||
|
||||
$user = Auth::user();
|
||||
$token = $user->createToken('main-token')->plainTextToken;
|
||||
|
||||
return response()->json([
|
||||
'message' => 'Успешный вход',
|
||||
'user' => $user,
|
||||
'token' => $token
|
||||
]);
|
||||
if (!$user || !Hash::check($request->password, $user->password)) {
|
||||
return response()->json(['message' => 'Неверный email или пароль'], 401);
|
||||
}
|
||||
|
||||
$token = $user->createToken('auth_token')->plainTextToken;
|
||||
|
||||
return response()->json([
|
||||
'access_token' => $token,
|
||||
'token_type' => 'Bearer',
|
||||
'user' => $user
|
||||
]);
|
||||
}
|
||||
}
|
||||
@@ -2,168 +2,92 @@
|
||||
|
||||
namespace App\Http\Controllers;
|
||||
|
||||
use App\Models\EmployeeAvailability;
|
||||
use App\Models\User;
|
||||
use Illuminate\Http\Request;
|
||||
use App\Models\EmployeeAvailability;
|
||||
|
||||
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();
|
||||
$availabilities = EmployeeAvailability::with('employee')
|
||||
->when($request->has('employee_id'), function ($query) use ($request) {
|
||||
$query->where('employee_id', $request->employee_id);
|
||||
})
|
||||
->when($request->has('date'), function ($query) use ($request) {
|
||||
$query->where('date', $request->date);
|
||||
})
|
||||
->get();
|
||||
|
||||
return response()->json($availabilities);
|
||||
}
|
||||
|
||||
// POST api/admin/availabilities - создать один слот
|
||||
|
||||
public function store(Request $request)
|
||||
{
|
||||
$request->validate([
|
||||
$validated = $request->validate([
|
||||
'employee_id' => 'required|exists:users,id',
|
||||
'date' => 'required|date',
|
||||
'starttime' => 'required',
|
||||
'endtime' => 'required|after:starttime',
|
||||
'isavailable' => 'boolean'
|
||||
'start_time' => 'required|date_format:H:i:s',
|
||||
'end_time' => 'required|date_format:H:i:s|after:start_time',
|
||||
'is_available' => 'boolean'
|
||||
]);
|
||||
|
||||
$availability = EmployeeAvailability::create($request->all());
|
||||
|
||||
$availability = EmployeeAvailability::create($validated);
|
||||
|
||||
return response()->json($availability, 201);
|
||||
}
|
||||
|
||||
// POST api/admin/availabilities/bulk - создать несколько слотов
|
||||
|
||||
public function bulkStore(Request $request)
|
||||
{
|
||||
$request->validate([
|
||||
$validated = $request->validate([
|
||||
'employee_id' => 'required|exists:users,id',
|
||||
'date' => 'required|date',
|
||||
'intervals' => 'required|array|min:1'
|
||||
'intervals' => 'required|array'
|
||||
]);
|
||||
|
||||
$availabilities = [];
|
||||
|
||||
foreach ($request->intervals as $interval) {
|
||||
$availability = EmployeeAvailability::create([
|
||||
EmployeeAvailability::create([
|
||||
'employee_id' => $request->employee_id,
|
||||
'date' => $request->date,
|
||||
'starttime' => $interval['start'],
|
||||
'endtime' => $interval['end'],
|
||||
'isavailable' => true
|
||||
'start_time' => $interval['start'],
|
||||
'end_time' => $interval['end'],
|
||||
'is_available' => true
|
||||
]);
|
||||
$availabilities[] = $availability;
|
||||
}
|
||||
|
||||
return response()->json($availabilities, 201);
|
||||
|
||||
return response()->json(['message' => 'Расписание добавлено']);
|
||||
}
|
||||
|
||||
// DELETE api/admin/availabilities/{id} - удалить слот (брони остаются!)
|
||||
|
||||
public function destroy($id)
|
||||
{
|
||||
$availability = EmployeeAvailability::findOrFail($id);
|
||||
$availability->delete();
|
||||
|
||||
return response()->json(['message' => 'Слот удален из расписания (брони сохранены)']);
|
||||
|
||||
return response()->json(['message' => 'Слот удалён']);
|
||||
}
|
||||
|
||||
// ✅ Единственный метод publicAvailability
|
||||
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 мин
|
||||
{
|
||||
$serviceId = $request->query('service_id');
|
||||
$date = $request->query('date');
|
||||
|
||||
if (!$serviceId || !$date) {
|
||||
return response()->json([]);
|
||||
}
|
||||
|
||||
$availabilities = EmployeeAvailability::where('date', $date)
|
||||
->where('is_available', true)
|
||||
->get();
|
||||
|
||||
$slots = [];
|
||||
foreach ($availabilities as $avail) {
|
||||
$slots[] = [
|
||||
'employee_id' => $avail->employee_id,
|
||||
'start' => substr($avail->start_time, 0, 5),
|
||||
'end' => substr($avail->end_time, 0, 5),
|
||||
];
|
||||
}
|
||||
|
||||
return response()->json($slots);
|
||||
}
|
||||
|
||||
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
|
||||
]);
|
||||
}
|
||||
}
|
||||
@@ -2,165 +2,112 @@
|
||||
|
||||
namespace App\Http\Controllers;
|
||||
|
||||
use App\Models\Booking;
|
||||
use App\Models\Services;
|
||||
use App\Models\EmployeeAvailability;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Str;
|
||||
use App\Models\Booking;
|
||||
use App\Models\Service;
|
||||
use App\Models\User;
|
||||
|
||||
class BookingsController extends Controller
|
||||
{
|
||||
public function store(Request $request)
|
||||
{
|
||||
$request->validate([
|
||||
$validated = $request->validate([
|
||||
'service_id' => 'required|exists:services,id',
|
||||
'employee_id' => 'required|exists:users,id',
|
||||
'date' => 'required|date',
|
||||
'starttime' => 'required'
|
||||
'start_time' => 'required|date_format:H:i:s'
|
||||
]);
|
||||
|
||||
$clientId = auth()->id();
|
||||
if (!$clientId) {
|
||||
return response()->json(['error' => 'Авторизация обязательна'], 401);
|
||||
}
|
||||
// Получаем длительность услуги
|
||||
$service = Service::findOrFail($validated['service_id']);
|
||||
$duration = $service->duration_minutes;
|
||||
|
||||
$service = Services::where('id', $request->service_id)
|
||||
->where('isactive', true)
|
||||
->first();
|
||||
if (!$service) {
|
||||
return response()->json(['error' => 'Услуга неактивна или не найдена'], 400);
|
||||
}
|
||||
// Вычисляем end_time
|
||||
$start = new \DateTime($validated['start_time']);
|
||||
$end = clone $start;
|
||||
$end->modify("+$duration minutes");
|
||||
$end_time = $end->format('H:i:s');
|
||||
|
||||
$durationMinutes = $service->durationminutes;
|
||||
$endtime = date('H:i:s', strtotime($request->starttime . " +{$durationMinutes} minutes"));
|
||||
|
||||
$availability = EmployeeAvailability::where('employee_id', $request->employee_id)
|
||||
->where('date', $request->date)
|
||||
->where('starttime', '<=', $request->starttime)
|
||||
->where('endtime', '>=', $endtime)
|
||||
->where('isavailable', true)
|
||||
->first();
|
||||
|
||||
if (!$availability) {
|
||||
return response()->json(['error' => 'Сотрудник недоступен в это время'], 400);
|
||||
}
|
||||
|
||||
$bookingExists = Booking::where('employee_id', $request->employee_id)
|
||||
->where('bookingdate', $request->date)
|
||||
->where('starttime', $request->starttime)
|
||||
->whereIn('status', ['confirmed', 'completed'])
|
||||
// Проверяем, свободен ли слот
|
||||
$conflict = Booking::where('employee_id', $validated['employee_id'])
|
||||
->where('booking_date', $validated['date'])
|
||||
->where('start_time', '<', $end_time)
|
||||
->where('end_time', '>', $validated['start_time'])
|
||||
->exists();
|
||||
|
||||
if ($bookingExists) {
|
||||
return response()->json(['error' => 'Слот уже забронирован'], 400);
|
||||
if ($conflict) {
|
||||
return response()->json(['message' => 'Слот занят'], 400);
|
||||
}
|
||||
|
||||
$bookingNumber = 'CL-' . date('Y') . '-' . str_pad(Booking::count() + 1, 4, '0', STR_PAD_LEFT);
|
||||
|
||||
// Создаём бронирование
|
||||
$booking = Booking::create([
|
||||
'bookingnumber' => $bookingNumber,
|
||||
'client_id' => $clientId,
|
||||
'employee_id' => $request->employee_id,
|
||||
'service_id' => $request->service_id,
|
||||
'bookingdate' => $request->date,
|
||||
'starttime' => $request->starttime,
|
||||
'endtime' => $endtime,
|
||||
'booking_number' => 'CL-' . date('Y') . '-' . str_pad(Booking::count() + 1, 4, '0', STR_PAD_LEFT),
|
||||
'client_id' => auth()->id(),
|
||||
'employee_id' => $validated['employee_id'],
|
||||
'service_id' => $validated['service_id'],
|
||||
'booking_date' => $validated['date'],
|
||||
'start_time' => $validated['start_time'],
|
||||
'end_time' => $end_time,
|
||||
'status' => 'confirmed'
|
||||
]);
|
||||
|
||||
return response()->json([
|
||||
'booking' => $booking,
|
||||
'message' => 'Бронирование создано №' . $bookingNumber
|
||||
], 201);
|
||||
return response()->json($booking, 201);
|
||||
}
|
||||
|
||||
public function cancel(Request $request, $id)
|
||||
public function clientIndex()
|
||||
{
|
||||
$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
|
||||
]);
|
||||
}
|
||||
|
||||
public function adminCancel(Request $request, $id)
|
||||
{
|
||||
$booking = Booking::findOrFail($id);
|
||||
|
||||
if (!auth()->user()->isEmployeeOrAdmin()) {
|
||||
return response()->json(['error' => 'Доступ только для админов/сотрудников'], 403);
|
||||
}
|
||||
|
||||
$booking->update([
|
||||
'status' => 'cancelled',
|
||||
'cancelledby' => 'admin',
|
||||
'cancelreason' => $request->reason ?? null
|
||||
]);
|
||||
|
||||
return response()->json([
|
||||
'message' => 'Бронь отменена администратором',
|
||||
'booking' => $booking
|
||||
]);
|
||||
}
|
||||
|
||||
public function clientIndex(Request $request)
|
||||
{
|
||||
$clientId = auth()->id();
|
||||
|
||||
$query = Booking::where('client_id', $clientId);
|
||||
|
||||
if ($request->date) {
|
||||
$query->where('bookingdate', $request->date);
|
||||
}
|
||||
if ($request->status) {
|
||||
$query->where('status', $request->status);
|
||||
}
|
||||
|
||||
$bookings = $query->with(['service', 'employee'])
|
||||
->orderBy('bookingdate', 'desc')
|
||||
->orderBy('starttime', 'asc')
|
||||
->get();
|
||||
|
||||
$bookings = Booking::where('client_id', auth()->id())->get();
|
||||
return response()->json($bookings);
|
||||
}
|
||||
|
||||
public function adminIndex(Request $request)
|
||||
// adminIndex
|
||||
public function adminIndex()
|
||||
{
|
||||
if (!auth()->user()->isEmployeeOrAdmin()) {
|
||||
return response()->json(['error' => 'Доступ запрещен'], 403);
|
||||
}
|
||||
|
||||
$query = Booking::with(['service', 'client', 'employee']);
|
||||
|
||||
if ($request->date) {
|
||||
$query->where('bookingdate', $request->date);
|
||||
}
|
||||
if ($request->status) {
|
||||
$query->where('status', $request->status);
|
||||
}
|
||||
if ($request->employee_id) {
|
||||
$query->where('employee_id', $request->employee_id);
|
||||
}
|
||||
|
||||
$bookings = $query->orderBy('bookingdate', 'desc')
|
||||
->orderBy('starttime', 'asc')
|
||||
$bookings = Booking::with(['client', 'employee', 'service'])
|
||||
->orderBy('booking_date', 'desc')
|
||||
->get();
|
||||
|
||||
return response()->json($bookings);
|
||||
}
|
||||
|
||||
public function cancel($id)
|
||||
{
|
||||
$booking = Booking::findOrFail($id);
|
||||
|
||||
if ($booking->client_id !== auth()->id()) {
|
||||
return response()->json(['message' => 'Нет прав'], 403);
|
||||
}
|
||||
|
||||
$booking->update([
|
||||
'status' => 'cancelled',
|
||||
'cancelled_by' => 'client',
|
||||
'cancel_reason' => request('reason')
|
||||
]);
|
||||
|
||||
return response()->json(['message' => 'Бронь отменена']);
|
||||
}
|
||||
|
||||
// adminCancel
|
||||
public function adminCancel($id)
|
||||
{
|
||||
$booking = Booking::findOrFail($id);
|
||||
$booking->update([
|
||||
'status' => 'cancelled',
|
||||
'cancelled_by' => 'admin',
|
||||
'cancel_reason' => request('reason')
|
||||
]);
|
||||
|
||||
return response()->json(['message' => 'Бронь отменена администратором']);
|
||||
}
|
||||
|
||||
// Назначение сотрудника
|
||||
public function assignEmployee(Request $request, $id)
|
||||
{
|
||||
$request->validate(['employee_id' => 'required|exists:users,id']);
|
||||
|
||||
$booking = Booking::findOrFail($id);
|
||||
$booking->employee_id = $request->employee_id;
|
||||
$booking->save();
|
||||
|
||||
return response()->json($booking);
|
||||
}
|
||||
}
|
||||
@@ -2,78 +2,60 @@
|
||||
|
||||
namespace App\Http\Controllers;
|
||||
|
||||
use App\Models\Services;
|
||||
use Illuminate\Http\Request;
|
||||
use App\Models\Service;
|
||||
|
||||
class ServicesController extends Controller
|
||||
{
|
||||
// GET api/admin/services - список активных услуг
|
||||
public function index()
|
||||
{
|
||||
$services = Services::where('isactive', true)->get();
|
||||
$services = Service::all();
|
||||
return response()->json($services);
|
||||
}
|
||||
|
||||
// POST api/admin/services - создать услугу
|
||||
|
||||
public function store(Request $request)
|
||||
{
|
||||
$request->validate([
|
||||
$validated = $request->validate([
|
||||
'name' => 'required|string|max:255',
|
||||
'description' => 'required|string',
|
||||
'durationminutes' => 'required|integer|min:1|max:500',
|
||||
'price' => 'required|numeric|min:0'
|
||||
'description' => 'nullable|string',
|
||||
'duration_minutes' => 'required|integer',
|
||||
'price' => 'required|numeric',
|
||||
'is_active' => 'boolean'
|
||||
]);
|
||||
|
||||
$service = Services::create([
|
||||
'name' => $request->name,
|
||||
'description' => $request->description,
|
||||
'durationminutes' => $request->durationminutes,
|
||||
'price' => $request->price,
|
||||
'isactive' => true // по умолчанию активна
|
||||
]);
|
||||
|
||||
|
||||
$service = Service::create($validated);
|
||||
|
||||
return response()->json($service, 201);
|
||||
}
|
||||
|
||||
// PUT api/admin/services/{id} - обновить услугу
|
||||
|
||||
public function update(Request $request, $id)
|
||||
{
|
||||
$service = Services::findOrFail($id);
|
||||
|
||||
$request->validate([
|
||||
$service = Service::findOrFail($id);
|
||||
|
||||
$validated = $request->validate([
|
||||
'name' => 'required|string|max:255',
|
||||
'description' => 'required|string',
|
||||
'durationminutes' => 'required|integer|min:1|max:500',
|
||||
'price' => 'required|numeric|min:0'
|
||||
'description' => 'nullable|string',
|
||||
'duration_minutes' => 'required|integer',
|
||||
'price' => 'required|numeric',
|
||||
'is_active' => 'boolean'
|
||||
]);
|
||||
|
||||
$service->update([
|
||||
'name' => $request->name,
|
||||
'description' => $request->description,
|
||||
'durationminutes' => $request->durationminutes,
|
||||
'price' => $request->price,
|
||||
]);
|
||||
|
||||
|
||||
$service->update($validated);
|
||||
|
||||
return response()->json($service);
|
||||
}
|
||||
|
||||
// DELETE api/admin/services/{id} - только если нет активных броней
|
||||
public function destroy($id)
|
||||
{
|
||||
$service = Services::findOrFail($id);
|
||||
|
||||
// ПРОВЕРКА: нельзя удалить услугу с активными бронями
|
||||
$activeBookings = \App\Models\Booking::where('service_id', $id)
|
||||
->where('status', '!=', 'cancelled')
|
||||
->exists();
|
||||
|
||||
if ($activeBookings) {
|
||||
return response()->json([
|
||||
'error' => 'Нельзя удалить услугу с активными бронями'
|
||||
], 400);
|
||||
|
||||
public function destroy($id)
|
||||
{
|
||||
$service = Service::findOrFail($id);
|
||||
$service->delete();
|
||||
|
||||
return response()->json(['message' => 'Услуга удалена']);
|
||||
}
|
||||
|
||||
$service->delete();
|
||||
return response()->json(['message' => 'Услуга удалена']);
|
||||
}
|
||||
|
||||
public function publicIndex()
|
||||
{
|
||||
$services = \App\Models\Service::where('is_active', true)->get();
|
||||
return response()->json($services);
|
||||
}
|
||||
}
|
||||
48
app/Http/Kernel.php
Normal file
48
app/Http/Kernel.php
Normal file
@@ -0,0 +1,48 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http;
|
||||
|
||||
use Illuminate\Foundation\Http\Kernel as HttpKernel;
|
||||
|
||||
class Kernel extends HttpKernel
|
||||
{
|
||||
protected $middleware = [
|
||||
\App\Http\Middleware\TrustProxies::class,
|
||||
\Illuminate\Http\Middleware\HandleCors::class,
|
||||
\App\Http\Middleware\PreventRequestsDuringMaintenance::class,
|
||||
\Illuminate\Foundation\Http\Middleware\ValidatePostSize::class,
|
||||
\App\Http\Middleware\TrimStrings::class,
|
||||
\Illuminate\Foundation\Http\Middleware\ConvertEmptyStringsToNull::class,
|
||||
];
|
||||
|
||||
protected $middlewareGroups = [
|
||||
'web' => [
|
||||
\App\Http\Middleware\EncryptCookies::class,
|
||||
\Illuminate\Cookie\Middleware\AddQueuedCookiesToResponse::class,
|
||||
\Illuminate\Session\Middleware\StartSession::class,
|
||||
\Illuminate\View\Middleware\ShareErrorsFromSession::class,
|
||||
\App\Http\Middleware\VerifyCsrfToken::class,
|
||||
\Illuminate\Routing\Middleware\SubstituteBindings::class,
|
||||
],
|
||||
|
||||
'api' => [
|
||||
\Illuminate\Routing\Middleware\ThrottleRequests::class.':api',
|
||||
\Illuminate\Routing\Middleware\SubstituteBindings::class,
|
||||
],
|
||||
];
|
||||
|
||||
protected $routeMiddleware = [
|
||||
'auth' => \App\Http\Middleware\Authenticate::class,
|
||||
'auth.basic' => \Illuminate\Auth\Middleware\AuthenticateWithBasicAuth::class,
|
||||
'auth.session' => \Illuminate\Session\Middleware\AuthenticateSession::class,
|
||||
'cache.headers' => \Illuminate\Http\Middleware\SetCacheHeaders::class,
|
||||
'can' => \Illuminate\Auth\Middleware\Authorize::class,
|
||||
'guest' => \App\Http\Middleware\RedirectIfAuthenticated::class,
|
||||
'password.confirm' => \Illuminate\Auth\Middleware\RequirePassword::class,
|
||||
'signed' => \App\Http\Middleware\ValidateSignature::class,
|
||||
'throttle' => \Illuminate\Routing\Middleware\ThrottleRequests::class,
|
||||
'verified' => \Illuminate\Auth\Middleware\EnsureEmailIsVerified::class,
|
||||
|
||||
'role' => \App\Http\Middleware\CheckRole::class,
|
||||
];
|
||||
}
|
||||
@@ -1,5 +1,7 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Middleware;
|
||||
|
||||
use Closure;
|
||||
use Illuminate\Http\Request;
|
||||
|
||||
@@ -7,10 +9,14 @@ class CheckRole
|
||||
{
|
||||
public function handle(Request $request, Closure $next, $role)
|
||||
{
|
||||
if (!auth()->check() || !auth()->user()->isEmployeeOrAdmin()) {
|
||||
return response()->json(['error' => 'Доступ запрещен'], 403);
|
||||
if (!$request->user()) {
|
||||
return response()->json(['message' => 'Unauthorized'], 401);
|
||||
}
|
||||
|
||||
if ($request->user()->role !== $role) {
|
||||
return response()->json(['message' => 'Access denied'], 403);
|
||||
}
|
||||
|
||||
return $next($request);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,39 +1,42 @@
|
||||
<?php
|
||||
|
||||
namespace App\Models;
|
||||
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||
// бронирование клиентов
|
||||
class Booking extends Model {
|
||||
|
||||
class Booking extends Model
|
||||
{
|
||||
use HasFactory;
|
||||
|
||||
protected $table = 'bookings';
|
||||
|
||||
|
||||
protected $fillable = [
|
||||
'bookingnumber',
|
||||
'booking_number',
|
||||
'client_id',
|
||||
'employee_id',
|
||||
'service_id',
|
||||
'bookingdate',
|
||||
'starttime',
|
||||
'endtime',
|
||||
'booking_date',
|
||||
'start_time',
|
||||
'end_time',
|
||||
'status',
|
||||
'cancelledby',
|
||||
'cancelreason'
|
||||
'cancelled_by',
|
||||
'cancel_reason'
|
||||
];
|
||||
|
||||
// списки броней
|
||||
public function service()
|
||||
{
|
||||
return $this->belongsTo(Services::class);
|
||||
}
|
||||
|
||||
// Связь с клиентом
|
||||
public function client()
|
||||
{
|
||||
return $this->belongsTo(User::class, 'client_id');
|
||||
}
|
||||
|
||||
|
||||
// Связь со сотрудником
|
||||
public function employee()
|
||||
{
|
||||
return $this->belongsTo(User::class, 'employee_id');
|
||||
}
|
||||
}
|
||||
|
||||
// Связь с услугой
|
||||
public function service()
|
||||
{
|
||||
return $this->belongsTo(Service::class);
|
||||
}
|
||||
}
|
||||
@@ -1,10 +1,16 @@
|
||||
<?php
|
||||
|
||||
namespace App\Models;
|
||||
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||
// расписание сотрудниĸов
|
||||
class EmployeeAvailability extends Model {
|
||||
use HasFactory;
|
||||
protected $table = 'employee_availabilities';
|
||||
protected $fillable = ['employee_id','date','starttime','endtime','isavailable'];
|
||||
}
|
||||
|
||||
class EmployeeAvailability extends Model
|
||||
{
|
||||
protected $fillable = [
|
||||
'employee_id',
|
||||
'date',
|
||||
'start_time',
|
||||
'end_time',
|
||||
'is_available'
|
||||
];
|
||||
}
|
||||
@@ -2,24 +2,24 @@
|
||||
|
||||
namespace App\Models;
|
||||
|
||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||
|
||||
class Services extends Model // услуги ĸлининга
|
||||
class Service extends Model
|
||||
{
|
||||
use HasFactory;
|
||||
|
||||
protected $fillable = [
|
||||
'name',
|
||||
'description',
|
||||
'durationminutes',
|
||||
'duration_minutes',
|
||||
'price',
|
||||
'isactive',
|
||||
'is_active'
|
||||
];
|
||||
|
||||
// Простая связь с bookings, если нужно
|
||||
// Связь с бронированиями
|
||||
public function bookings()
|
||||
{
|
||||
return $this->hasMany(Booking::class);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -2,44 +2,24 @@
|
||||
|
||||
namespace App\Models;
|
||||
|
||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||
use Illuminate\Foundation\Auth\User as Authenticatable;
|
||||
use Illuminate\Notifications\Notifiable;
|
||||
use Laravel\Sanctum\HasApiTokens;
|
||||
|
||||
class User extends Authenticatable // все пользователи системы
|
||||
class User extends Authenticatable
|
||||
{
|
||||
use HasApiTokens, HasFactory, Notifiable;
|
||||
use HasApiTokens, Notifiable;
|
||||
|
||||
protected $fillable = [
|
||||
'name',
|
||||
'email',
|
||||
'password',
|
||||
'role',
|
||||
'role',
|
||||
'phone'
|
||||
];
|
||||
|
||||
protected $hidden = [
|
||||
'password',
|
||||
'remember_token',
|
||||
];
|
||||
|
||||
protected function casts(): array
|
||||
{
|
||||
return [
|
||||
'email_verified_at' => 'datetime',
|
||||
'password' => 'hashed',
|
||||
];
|
||||
}
|
||||
|
||||
// Проверяет админ или сотрудник
|
||||
public function isEmployeeOrAdmin()
|
||||
{
|
||||
return $this->role == 'employee' || $this->role == 'admin';
|
||||
}
|
||||
|
||||
// Для запросов - все сотрудники и админы
|
||||
public static function scopeEmployeeOrAdmin($query)
|
||||
{
|
||||
return $query->whereIn('role', ['employee', 'admin']);
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user