Files
sam-manage/app/Models/Sales/SalesConsultation.php
pro 329c58e63b refactor:영업관리 데이터를 DB 테이블로 변경
- 모델 추가: SalesPartner, SalesTenantManagement, SalesScenarioChecklist, SalesConsultation
- 모델 위치 이동: app/Models/ → app/Models/Sales/
- 컨트롤러 수정: 캐시 대신 DB 모델 사용
- 뷰 수정: Eloquent 모델 속성 사용

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-29 06:42:32 +09:00

249 lines
6.1 KiB
PHP

<?php
namespace App\Models\Sales;
use App\Models\Tenants\Tenant;
use App\Models\User;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsTo;
use Illuminate\Database\Eloquent\SoftDeletes;
use Illuminate\Support\Facades\Storage;
/**
* 영업 상담 기록 모델 (텍스트, 음성, 첨부파일)
*
* @property int $id
* @property int $tenant_id
* @property string $scenario_type (sales/manager)
* @property int|null $step_id
* @property string $consultation_type (text/audio/file)
* @property string|null $content
* @property string|null $file_path
* @property string|null $file_name
* @property int|null $file_size
* @property string|null $file_type
* @property string|null $transcript
* @property int|null $duration
* @property int $created_by
*/
class SalesConsultation extends Model
{
use SoftDeletes;
protected $table = 'sales_consultations';
protected $fillable = [
'tenant_id',
'scenario_type',
'step_id',
'consultation_type',
'content',
'file_path',
'file_name',
'file_size',
'file_type',
'transcript',
'duration',
'created_by',
];
protected $casts = [
'step_id' => 'integer',
'file_size' => 'integer',
'duration' => 'integer',
];
/**
* 상담 유형 상수
*/
const TYPE_TEXT = 'text';
const TYPE_AUDIO = 'audio';
const TYPE_FILE = 'file';
/**
* 테넌트 관계
*/
public function tenant(): BelongsTo
{
return $this->belongsTo(Tenant::class);
}
/**
* 작성자 관계
*/
public function creator(): BelongsTo
{
return $this->belongsTo(User::class, 'created_by');
}
/**
* 텍스트 상담 기록 생성
*/
public static function createText(int $tenantId, string $scenarioType, ?int $stepId, string $content): self
{
return self::create([
'tenant_id' => $tenantId,
'scenario_type' => $scenarioType,
'step_id' => $stepId,
'consultation_type' => self::TYPE_TEXT,
'content' => $content,
'created_by' => auth()->id(),
]);
}
/**
* 음성 상담 기록 생성
*/
public static function createAudio(
int $tenantId,
string $scenarioType,
?int $stepId,
string $filePath,
string $fileName,
int $fileSize,
?string $transcript = null,
?int $duration = null
): self {
return self::create([
'tenant_id' => $tenantId,
'scenario_type' => $scenarioType,
'step_id' => $stepId,
'consultation_type' => self::TYPE_AUDIO,
'file_path' => $filePath,
'file_name' => $fileName,
'file_size' => $fileSize,
'file_type' => 'audio/webm',
'transcript' => $transcript,
'duration' => $duration,
'created_by' => auth()->id(),
]);
}
/**
* 파일 상담 기록 생성
*/
public static function createFile(
int $tenantId,
string $scenarioType,
?int $stepId,
string $filePath,
string $fileName,
int $fileSize,
string $fileType
): self {
return self::create([
'tenant_id' => $tenantId,
'scenario_type' => $scenarioType,
'step_id' => $stepId,
'consultation_type' => self::TYPE_FILE,
'file_path' => $filePath,
'file_name' => $fileName,
'file_size' => $fileSize,
'file_type' => $fileType,
'created_by' => auth()->id(),
]);
}
/**
* 파일 삭제 (storage 포함)
*/
public function deleteWithFile(): bool
{
if ($this->file_path && Storage::disk('local')->exists($this->file_path)) {
Storage::disk('local')->delete($this->file_path);
}
return $this->delete();
}
/**
* 포맷된 duration Accessor
*/
public function getFormattedDurationAttribute(): ?string
{
if (!$this->duration) {
return null;
}
$minutes = floor($this->duration / 60);
$seconds = $this->duration % 60;
return sprintf('%02d:%02d', $minutes, $seconds);
}
/**
* 포맷된 file size Accessor
*/
public function getFormattedFileSizeAttribute(): ?string
{
if (!$this->file_size) {
return null;
}
if ($this->file_size < 1024) {
return $this->file_size . ' B';
} elseif ($this->file_size < 1024 * 1024) {
return round($this->file_size / 1024, 1) . ' KB';
} else {
return round($this->file_size / (1024 * 1024), 1) . ' MB';
}
}
/**
* 테넌트 + 시나리오 타입으로 조회
*/
public static function getByTenantAndType(int $tenantId, string $scenarioType, ?int $stepId = null)
{
$query = self::where('tenant_id', $tenantId)
->where('scenario_type', $scenarioType)
->with('creator')
->orderBy('created_at', 'desc');
if ($stepId !== null) {
$query->where('step_id', $stepId);
}
return $query->get();
}
/**
* 시나리오 타입 스코프
*/
public function scopeByScenarioType($query, string $type)
{
return $query->where('scenario_type', $type);
}
/**
* 상담 유형 스코프
*/
public function scopeByType($query, string $type)
{
return $query->where('consultation_type', $type);
}
/**
* 텍스트만 스코프
*/
public function scopeTextOnly($query)
{
return $query->where('consultation_type', self::TYPE_TEXT);
}
/**
* 오디오만 스코프
*/
public function scopeAudioOnly($query)
{
return $query->where('consultation_type', self::TYPE_AUDIO);
}
/**
* 파일만 스코프
*/
public function scopeFileOnly($query)
{
return $query->where('consultation_type', self::TYPE_FILE);
}
}