Files
sam-api/app/Models/CompanyRequest.php
hskwon 7781253491 feat: Phase 8.3 회사 추가 API 구현
- 사업자등록번호 유효성 검사 API (바로빌 연동)
- 회사 추가 신청/승인/반려 워크플로우
- 신청 승인 시 테넌트 자동 생성 및 사용자 연결
- 관리자용 신청 목록/상세 조회
- 사용자용 내 신청 목록 조회
- Swagger 문서 및 i18n 메시지 추가
2025-12-22 15:30:38 +09:00

238 lines
6.0 KiB
PHP

<?php
namespace App\Models;
use App\Models\Members\User;
use App\Models\Tenants\Tenant;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsTo;
/**
* 회사 추가 신청 모델
*
* @property int $id
* @property int $user_id 신청자 ID
* @property string $business_number 사업자등록번호
* @property string $company_name 회사명
* @property string|null $ceo_name 대표자명
* @property string|null $address 주소
* @property string|null $phone 전화번호
* @property string|null $email 이메일
* @property string $status 상태 (pending, approved, rejected)
* @property string|null $message 신청 메시지
* @property string|null $reject_reason 반려 사유
* @property array|null $barobill_response 바로빌 검증 응답
* @property int|null $approved_by 승인/반려 처리자
* @property int|null $created_tenant_id 생성된 테넌트 ID
* @property \Carbon\Carbon|null $processed_at 처리일시
* @property \Carbon\Carbon $created_at
* @property \Carbon\Carbon $updated_at
*/
class CompanyRequest extends Model
{
// =========================================================================
// 상수 정의
// =========================================================================
/** 상태 */
public const STATUS_PENDING = 'pending';
public const STATUS_APPROVED = 'approved';
public const STATUS_REJECTED = 'rejected';
public const STATUSES = [
self::STATUS_PENDING,
self::STATUS_APPROVED,
self::STATUS_REJECTED,
];
/** 상태 라벨 */
public const STATUS_LABELS = [
self::STATUS_PENDING => '대기중',
self::STATUS_APPROVED => '승인',
self::STATUS_REJECTED => '반려',
];
// =========================================================================
// 모델 설정
// =========================================================================
protected $fillable = [
'user_id',
'business_number',
'company_name',
'ceo_name',
'address',
'phone',
'email',
'status',
'message',
'reject_reason',
'barobill_response',
'approved_by',
'created_tenant_id',
'processed_at',
];
protected $casts = [
'barobill_response' => 'array',
'processed_at' => 'datetime',
];
protected $attributes = [
'status' => self::STATUS_PENDING,
];
// =========================================================================
// 관계
// =========================================================================
/**
* 신청자
*/
public function user(): BelongsTo
{
return $this->belongsTo(User::class);
}
/**
* 처리자 (승인/반려)
*/
public function approver(): BelongsTo
{
return $this->belongsTo(User::class, 'approved_by');
}
/**
* 생성된 테넌트
*/
public function createdTenant(): BelongsTo
{
return $this->belongsTo(Tenant::class, 'created_tenant_id');
}
// =========================================================================
// 스코프
// =========================================================================
/**
* 대기중인 신청만
*/
public function scopePending($query)
{
return $query->where('status', self::STATUS_PENDING);
}
/**
* 승인된 신청만
*/
public function scopeApproved($query)
{
return $query->where('status', self::STATUS_APPROVED);
}
/**
* 반려된 신청만
*/
public function scopeRejected($query)
{
return $query->where('status', self::STATUS_REJECTED);
}
/**
* 상태 필터
*/
public function scopeOfStatus($query, string $status)
{
return $query->where('status', $status);
}
// =========================================================================
// 접근자
// =========================================================================
/**
* 상태 라벨
*/
public function getStatusLabelAttribute(): string
{
return self::STATUS_LABELS[$this->status] ?? $this->status;
}
/**
* 대기중 여부
*/
public function getIsPendingAttribute(): bool
{
return $this->status === self::STATUS_PENDING;
}
/**
* 승인됨 여부
*/
public function getIsApprovedAttribute(): bool
{
return $this->status === self::STATUS_APPROVED;
}
/**
* 반려됨 여부
*/
public function getIsRejectedAttribute(): bool
{
return $this->status === self::STATUS_REJECTED;
}
/**
* 사업자등록번호 포맷 (하이픈 포함)
*/
public function getFormattedBusinessNumberAttribute(): string
{
$num = preg_replace('/[^0-9]/', '', $this->business_number);
if (strlen($num) === 10) {
return substr($num, 0, 3).'-'.substr($num, 3, 2).'-'.substr($num, 5, 5);
}
return $this->business_number;
}
// =========================================================================
// 헬퍼 메서드
// =========================================================================
/**
* 승인 처리
*/
public function approve(int $approverId, int $tenantId): bool
{
if (! $this->is_pending) {
return false;
}
$this->status = self::STATUS_APPROVED;
$this->approved_by = $approverId;
$this->created_tenant_id = $tenantId;
$this->processed_at = now();
return $this->save();
}
/**
* 반려 처리
*/
public function reject(int $approverId, ?string $reason = null): bool
{
if (! $this->is_pending) {
return false;
}
$this->status = self::STATUS_REJECTED;
$this->approved_by = $approverId;
$this->reject_reason = $reason;
$this->processed_at = now();
return $this->save();
}
}