Files
sam-api/app/Services/CalendarScheduleService.php
김보곤 1a2350db7d feat: [calendar] 달력 일정 관리 API 구현
- GET /api/v1/calendar-schedules — 연도별 일정 목록 조회
- GET /api/v1/calendar-schedules/stats — 통계 조회
- GET /api/v1/calendar-schedules/{id} — 단건 조회
- POST /api/v1/calendar-schedules — 등록
- PUT /api/v1/calendar-schedules/{id} — 수정
- DELETE /api/v1/calendar-schedules/{id} — 삭제
- POST /api/v1/calendar-schedules/bulk — 대량 등록
2026-02-26 14:29:12 +09:00

181 lines
5.1 KiB
PHP

<?php
namespace App\Services;
use App\Models\Commons\Holiday;
use Symfony\Component\HttpKernel\Exception\HttpException;
class CalendarScheduleService extends Service
{
/**
* 연도별 일정 목록 조회
*/
public function list(int $year, ?string $type = null): array
{
$query = Holiday::forTenant($this->tenantId())
->forYear($year)
->orderBy('start_date');
if ($type) {
$query->where('type', $type);
}
return $query->get()->map(function ($h) {
return [
'id' => $h->id,
'name' => $h->name,
'type' => $h->type,
'start_date' => $h->start_date->format('Y-m-d'),
'end_date' => $h->end_date->format('Y-m-d'),
'days' => $h->start_date->diffInDays($h->end_date) + 1,
'is_recurring' => $h->is_recurring,
'memo' => $h->memo,
'created_at' => $h->created_at?->toIso8601String(),
'updated_at' => $h->updated_at?->toIso8601String(),
];
})->all();
}
/**
* 통계 조회
*/
public function stats(int $year): array
{
$tenantId = $this->tenantId();
$holidays = Holiday::forTenant($tenantId)->forYear($year)->get();
$totalDays = $holidays->sum(function ($h) {
return $h->start_date->diffInDays($h->end_date) + 1;
});
return [
'total_count' => $holidays->count(),
'total_holiday_days' => $totalDays,
'public_holiday_count' => $holidays->where('type', 'public_holiday')->count(),
];
}
/**
* 단건 조회
*/
public function show(int $id): array
{
$h = Holiday::forTenant($this->tenantId())->findOrFail($id);
return [
'id' => $h->id,
'name' => $h->name,
'type' => $h->type,
'start_date' => $h->start_date->format('Y-m-d'),
'end_date' => $h->end_date->format('Y-m-d'),
'days' => $h->start_date->diffInDays($h->end_date) + 1,
'is_recurring' => $h->is_recurring,
'memo' => $h->memo,
'created_at' => $h->created_at?->toIso8601String(),
'updated_at' => $h->updated_at?->toIso8601String(),
];
}
/**
* 등록
*/
public function store(array $data): array
{
$tenantId = $this->tenantId();
$exists = Holiday::forTenant($tenantId)
->where('start_date', $data['start_date'])
->where('end_date', $data['end_date'])
->where('name', $data['name'])
->exists();
if ($exists) {
throw new HttpException(422, __('error.duplicate'));
}
$holiday = Holiday::create([
'tenant_id' => $tenantId,
'start_date' => $data['start_date'],
'end_date' => $data['end_date'],
'name' => $data['name'],
'type' => $data['type'] ?? 'public_holiday',
'is_recurring' => $data['is_recurring'] ?? false,
'memo' => $data['memo'] ?? null,
'created_by' => $this->apiUserId(),
]);
return $this->show($holiday->id);
}
/**
* 수정
*/
public function update(int $id, array $data): array
{
$holiday = Holiday::forTenant($this->tenantId())->findOrFail($id);
$holiday->update([
'start_date' => $data['start_date'],
'end_date' => $data['end_date'],
'name' => $data['name'],
'type' => $data['type'],
'is_recurring' => $data['is_recurring'] ?? false,
'memo' => $data['memo'] ?? null,
'updated_by' => $this->apiUserId(),
]);
return $this->show($id);
}
/**
* 삭제
*/
public function delete(int $id): void
{
$holiday = Holiday::forTenant($this->tenantId())->findOrFail($id);
$holiday->delete();
}
/**
* 대량 등록
*/
public function bulkStore(array $schedules): array
{
$tenantId = $this->tenantId();
$userId = $this->apiUserId();
$count = 0;
$skipped = 0;
foreach ($schedules as $item) {
$exists = Holiday::forTenant($tenantId)
->where('start_date', $item['start_date'])
->where('end_date', $item['end_date'])
->where('name', $item['name'])
->exists();
if ($exists) {
$skipped++;
continue;
}
Holiday::create([
'tenant_id' => $tenantId,
'start_date' => $item['start_date'],
'end_date' => $item['end_date'],
'name' => $item['name'],
'type' => $item['type'] ?? 'public_holiday',
'is_recurring' => $item['is_recurring'] ?? false,
'memo' => $item['memo'] ?? null,
'created_by' => $userId,
]);
$count++;
}
return [
'created' => $count,
'skipped' => $skipped,
];
}
}