Files
sam-api/app/Models/Tenants/Site.php
hskwon ca5618be98 feat: 근무/출퇴근 설정 및 현장 관리 API 구현
- 근무 설정 API (GET/PUT /settings/work)
  - 근무유형, 소정근로시간, 연장근로시간, 근무요일, 출퇴근시간, 휴게시간
- 출퇴근 설정 API (GET/PUT /settings/attendance)
  - GPS 출퇴근, 허용 반경, 본사 위치 설정
- 현장 관리 API (CRUD /sites)
  - 현장 등록/수정/삭제, 활성화된 현장 목록(셀렉트박스용)
  - GPS 좌표 기반 위치 관리

마이그레이션: work_settings, attendance_settings, sites 테이블
모델: WorkSetting, AttendanceSetting, Site (BelongsToTenant, SoftDeletes)
서비스: WorkSettingService, SiteService
Swagger 문서 및 i18n 메시지 키 추가
2025-12-17 20:46:37 +09:00

126 lines
3.0 KiB
PHP

<?php
namespace App\Models\Tenants;
use App\Models\Members\User;
use App\Traits\BelongsToTenant;
use App\Traits\ModelTrait;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsTo;
use Illuminate\Database\Eloquent\SoftDeletes;
/**
* 현장 모델
*
* @property int $id
* @property int $tenant_id
* @property string $name
* @property string|null $address
* @property float|null $latitude
* @property float|null $longitude
* @property bool $is_active
* @property int|null $created_by
* @property int|null $updated_by
* @property int|null $deleted_by
*/
class Site extends Model
{
use BelongsToTenant, ModelTrait, SoftDeletes;
protected $table = 'sites';
protected $fillable = [
'tenant_id',
'name',
'address',
'latitude',
'longitude',
'is_active',
'created_by',
'updated_by',
'deleted_by',
];
protected $casts = [
'latitude' => 'decimal:8',
'longitude' => 'decimal:8',
'is_active' => 'boolean',
];
protected $attributes = [
'is_active' => true,
];
// =========================================================================
// 관계 정의
// =========================================================================
/**
* 생성자
*/
public function creator(): BelongsTo
{
return $this->belongsTo(User::class, 'created_by');
}
/**
* 수정자
*/
public function updater(): BelongsTo
{
return $this->belongsTo(User::class, 'updated_by');
}
// =========================================================================
// 헬퍼 메서드
// =========================================================================
/**
* GPS 좌표 설정 여부
*/
public function hasCoordinates(): bool
{
return $this->latitude !== null && $this->longitude !== null;
}
/**
* 좌표가 허용 범위 내인지 확인
*/
public function isWithinRadius(float $latitude, float $longitude, int $radiusMeters = 100): bool
{
if (! $this->hasCoordinates()) {
return true; // 좌표 미설정 시 항상 허용
}
$distance = $this->calculateDistance(
$this->latitude,
$this->longitude,
$latitude,
$longitude
);
return $distance <= $radiusMeters;
}
/**
* 두 좌표 간 거리 계산 (미터)
*/
private function calculateDistance(float $lat1, float $lon1, float $lat2, float $lon2): float
{
$earthRadius = 6371000;
$lat1Rad = deg2rad($lat1);
$lat2Rad = deg2rad($lat2);
$deltaLat = deg2rad($lat2 - $lat1);
$deltaLon = deg2rad($lon2 - $lon1);
$a = sin($deltaLat / 2) * sin($deltaLat / 2) +
cos($lat1Rad) * cos($lat2Rad) *
sin($deltaLon / 2) * sin($deltaLon / 2);
$c = 2 * atan2(sqrt($a), sqrt(1 - $a));
return $earthRadius * $c;
}
}