feat: Phase 8 SaaS 확장 - 구독관리/결제내역 API 추가
- 사용량 조회 API (GET /subscriptions/usage)
- 데이터 내보내기 API (POST/GET /subscriptions/export)
- 결제 명세서 API (GET /payments/{id}/statement)
- DataExport 모델 및 마이그레이션 추가
This commit is contained in:
206
app/Models/Tenants/DataExport.php
Normal file
206
app/Models/Tenants/DataExport.php
Normal file
@@ -0,0 +1,206 @@
|
||||
<?php
|
||||
|
||||
namespace App\Models\Tenants;
|
||||
|
||||
use App\Models\Members\User;
|
||||
use App\Traits\BelongsToTenant;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Illuminate\Database\Eloquent\Relations\BelongsTo;
|
||||
|
||||
/**
|
||||
* 데이터 내보내기 모델
|
||||
*
|
||||
* @property int $id
|
||||
* @property int $tenant_id 테넌트 ID
|
||||
* @property string $export_type 내보내기 유형
|
||||
* @property string $status 상태
|
||||
* @property string|null $file_path 파일 경로
|
||||
* @property string|null $file_name 파일명
|
||||
* @property int|null $file_size 파일 크기
|
||||
* @property array|null $options 옵션
|
||||
* @property \Carbon\Carbon|null $started_at 시작 시간
|
||||
* @property \Carbon\Carbon|null $completed_at 완료 시간
|
||||
* @property string|null $error_message 에러 메시지
|
||||
* @property int|null $created_by 생성자
|
||||
*/
|
||||
class DataExport extends Model
|
||||
{
|
||||
use BelongsToTenant;
|
||||
|
||||
// =========================================================================
|
||||
// 상수 정의
|
||||
// =========================================================================
|
||||
|
||||
/** 내보내기 유형 */
|
||||
public const TYPE_ALL = 'all';
|
||||
|
||||
public const TYPE_USERS = 'users';
|
||||
|
||||
public const TYPE_PRODUCTS = 'products';
|
||||
|
||||
public const TYPE_ORDERS = 'orders';
|
||||
|
||||
public const TYPE_CLIENTS = 'clients';
|
||||
|
||||
public const TYPES = [
|
||||
self::TYPE_ALL,
|
||||
self::TYPE_USERS,
|
||||
self::TYPE_PRODUCTS,
|
||||
self::TYPE_ORDERS,
|
||||
self::TYPE_CLIENTS,
|
||||
];
|
||||
|
||||
/** 상태 */
|
||||
public const STATUS_PENDING = 'pending';
|
||||
|
||||
public const STATUS_PROCESSING = 'processing';
|
||||
|
||||
public const STATUS_COMPLETED = 'completed';
|
||||
|
||||
public const STATUS_FAILED = 'failed';
|
||||
|
||||
public const STATUSES = [
|
||||
self::STATUS_PENDING,
|
||||
self::STATUS_PROCESSING,
|
||||
self::STATUS_COMPLETED,
|
||||
self::STATUS_FAILED,
|
||||
];
|
||||
|
||||
/** 상태 라벨 */
|
||||
public const STATUS_LABELS = [
|
||||
self::STATUS_PENDING => '대기중',
|
||||
self::STATUS_PROCESSING => '처리중',
|
||||
self::STATUS_COMPLETED => '완료',
|
||||
self::STATUS_FAILED => '실패',
|
||||
];
|
||||
|
||||
// =========================================================================
|
||||
// 모델 설정
|
||||
// =========================================================================
|
||||
|
||||
protected $fillable = [
|
||||
'tenant_id',
|
||||
'export_type',
|
||||
'status',
|
||||
'file_path',
|
||||
'file_name',
|
||||
'file_size',
|
||||
'options',
|
||||
'started_at',
|
||||
'completed_at',
|
||||
'error_message',
|
||||
'created_by',
|
||||
];
|
||||
|
||||
protected $casts = [
|
||||
'options' => 'array',
|
||||
'file_size' => 'integer',
|
||||
'started_at' => 'datetime',
|
||||
'completed_at' => 'datetime',
|
||||
];
|
||||
|
||||
protected $attributes = [
|
||||
'status' => self::STATUS_PENDING,
|
||||
];
|
||||
|
||||
// =========================================================================
|
||||
// 관계
|
||||
// =========================================================================
|
||||
|
||||
public function tenant(): BelongsTo
|
||||
{
|
||||
return $this->belongsTo(Tenant::class);
|
||||
}
|
||||
|
||||
public function creator(): BelongsTo
|
||||
{
|
||||
return $this->belongsTo(User::class, 'created_by');
|
||||
}
|
||||
|
||||
// =========================================================================
|
||||
// 접근자
|
||||
// =========================================================================
|
||||
|
||||
/**
|
||||
* 상태 라벨
|
||||
*/
|
||||
public function getStatusLabelAttribute(): string
|
||||
{
|
||||
return self::STATUS_LABELS[$this->status] ?? $this->status;
|
||||
}
|
||||
|
||||
/**
|
||||
* 파일 크기 포맷
|
||||
*/
|
||||
public function getFileSizeFormattedAttribute(): string
|
||||
{
|
||||
if (! $this->file_size) {
|
||||
return '-';
|
||||
}
|
||||
|
||||
$units = ['B', 'KB', 'MB', 'GB'];
|
||||
$bytes = max($this->file_size, 0);
|
||||
$pow = floor(($bytes ? log($bytes) : 0) / log(1024));
|
||||
$pow = min($pow, count($units) - 1);
|
||||
$bytes /= (1 << (10 * $pow));
|
||||
|
||||
return round($bytes, 2).' '.$units[$pow];
|
||||
}
|
||||
|
||||
/**
|
||||
* 완료 여부
|
||||
*/
|
||||
public function getIsCompletedAttribute(): bool
|
||||
{
|
||||
return $this->status === self::STATUS_COMPLETED;
|
||||
}
|
||||
|
||||
/**
|
||||
* 다운로드 가능 여부
|
||||
*/
|
||||
public function getIsDownloadableAttribute(): bool
|
||||
{
|
||||
return $this->status === self::STATUS_COMPLETED && $this->file_path;
|
||||
}
|
||||
|
||||
// =========================================================================
|
||||
// 헬퍼 메서드
|
||||
// =========================================================================
|
||||
|
||||
/**
|
||||
* 처리 시작
|
||||
*/
|
||||
public function markAsProcessing(): bool
|
||||
{
|
||||
$this->status = self::STATUS_PROCESSING;
|
||||
$this->started_at = now();
|
||||
|
||||
return $this->save();
|
||||
}
|
||||
|
||||
/**
|
||||
* 처리 완료
|
||||
*/
|
||||
public function markAsCompleted(string $filePath, string $fileName, int $fileSize): bool
|
||||
{
|
||||
$this->status = self::STATUS_COMPLETED;
|
||||
$this->file_path = $filePath;
|
||||
$this->file_name = $fileName;
|
||||
$this->file_size = $fileSize;
|
||||
$this->completed_at = now();
|
||||
|
||||
return $this->save();
|
||||
}
|
||||
|
||||
/**
|
||||
* 처리 실패
|
||||
*/
|
||||
public function markAsFailed(string $errorMessage): bool
|
||||
{
|
||||
$this->status = self::STATUS_FAILED;
|
||||
$this->error_message = $errorMessage;
|
||||
$this->completed_at = now();
|
||||
|
||||
return $this->save();
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user