Files
sam-api/app/Models/Qualitys/Inspection.php
권혁성 189b38c936 feat: Auditable 트레이트 구현 및 97개 모델 적용
- Auditable 트레이트 신규 생성 (bootAuditable 패턴)
  - creating: created_by/updated_by 자동 채우기
  - updating: updated_by 자동 채우기
  - deleting: deleted_by 채우기 + saveQuietly()
  - created/updated/deleted: audit_logs 자동 기록
- 기존 AuditLogger 패턴과 동일한 try/catch 조용한 실패
- 변경된 필드만 before/after 기록 (updated 이벤트)
- auditExclude 프로퍼티로 모델별 제외 필드 설정 가능
- 제외 대상: Attendance, StockTransaction, TodayIssue 등 고빈도/시스템 모델

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-29 15:33:54 +09:00

218 lines
5.4 KiB
PHP

<?php
namespace App\Models\Qualitys;
use App\Models\Items\Item;
use App\Models\Members\User;
use App\Traits\Auditable;
use App\Traits\BelongsToTenant;
use Illuminate\Database\Eloquent\Casts\Attribute;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\SoftDeletes;
/**
* 통합 검사 모델 (IQC/PQC/FQC)
*
* @property int $id
* @property int $tenant_id
* @property string $inspection_no 검사번호
* @property string $inspection_type 검사유형 (IQC, PQC, FQC)
* @property string $status 상태 (waiting, in_progress, completed)
* @property string|null $result 판정결과 (pass, fail)
* @property string $request_date 검사요청일
* @property string|null $inspection_date 검사일
* @property int|null $item_id 품목 ID
* @property string $lot_no LOT번호
* @property int|null $inspector_id 검사자 ID
* @property array|null $meta 메타정보 (process_name, quantity, unit 등)
* @property array|null $items 검사항목 배열
* @property array|null $attachments 첨부파일 배열
* @property array|null $extra 추가정보 (remarks, opinion 등)
*
* @mixin IdeHelperInspection
*/
class Inspection extends Model
{
use Auditable, BelongsToTenant, SoftDeletes;
protected $table = 'inspections';
protected $fillable = [
'tenant_id',
'inspection_no',
'inspection_type',
'status',
'result',
'request_date',
'inspection_date',
'item_id',
'lot_no',
'inspector_id',
'meta',
'items',
'attachments',
'extra',
'created_by',
'updated_by',
];
protected $casts = [
'meta' => 'array',
'items' => 'array',
'attachments' => 'array',
'extra' => 'array',
'request_date' => 'date',
'inspection_date' => 'date',
];
/**
* 검사 유형 상수
*/
public const TYPE_IQC = 'IQC'; // 수입검사 (Incoming Quality Control)
public const TYPE_PQC = 'PQC'; // 공정검사 (Process Quality Control)
public const TYPE_FQC = 'FQC'; // 최종검사 (Final Quality Control)
/**
* 상태 상수
*/
public const STATUS_WAITING = 'waiting';
public const STATUS_IN_PROGRESS = 'in_progress';
public const STATUS_COMPLETED = 'completed';
/**
* 판정결과 상수
*/
public const RESULT_PASS = 'pass';
public const RESULT_FAIL = 'fail';
// ===== Relationships =====
/**
* 품목
*/
public function item()
{
return $this->belongsTo(Item::class, 'item_id');
}
/**
* 검사자
*/
public function inspector()
{
return $this->belongsTo(User::class, 'inspector_id');
}
/**
* 생성자
*/
public function creator()
{
return $this->belongsTo(User::class, 'created_by');
}
// ===== Accessors (meta JSON 필드) =====
protected function processName(): Attribute
{
return Attribute::make(
get: fn () => $this->meta['process_name'] ?? null,
set: fn ($value) => $this->setMetaValue('process_name', $value),
);
}
protected function quantity(): Attribute
{
return Attribute::make(
get: fn () => $this->meta['quantity'] ?? null,
set: fn ($value) => $this->setMetaValue('quantity', $value),
);
}
protected function unit(): Attribute
{
return Attribute::make(
get: fn () => $this->meta['unit'] ?? null,
set: fn ($value) => $this->setMetaValue('unit', $value),
);
}
// ===== Accessors (extra JSON 필드) =====
protected function remarks(): Attribute
{
return Attribute::make(
get: fn () => $this->extra['remarks'] ?? null,
set: fn ($value) => $this->setExtraValue('remarks', $value),
);
}
protected function opinion(): Attribute
{
return Attribute::make(
get: fn () => $this->extra['opinion'] ?? null,
set: fn ($value) => $this->setExtraValue('opinion', $value),
);
}
// ===== Helper Methods =====
/**
* meta JSON 필드에 값 설정
*/
protected function setMetaValue(string $key, $value): array
{
$meta = $this->meta ?? [];
$meta[$key] = $value;
$this->attributes['meta'] = json_encode($meta);
return $meta;
}
/**
* extra JSON 필드에 값 설정
*/
protected function setExtraValue(string $key, $value): array
{
$extra = $this->extra ?? [];
$extra[$key] = $value;
$this->attributes['extra'] = json_encode($extra);
return $extra;
}
/**
* 검사번호 자동 생성
*/
public static function generateInspectionNo(int $tenantId, string $type): string
{
$prefix = match ($type) {
self::TYPE_IQC => 'IQC',
self::TYPE_PQC => 'PQC',
self::TYPE_FQC => 'FQC',
default => 'INS',
};
$date = now()->format('Ymd');
$lastNo = static::withoutGlobalScopes()
->where('tenant_id', $tenantId)
->where('inspection_no', 'like', "{$prefix}-{$date}-%")
->orderByDesc('inspection_no')
->value('inspection_no');
if ($lastNo) {
$seq = (int) substr($lastNo, -4) + 1;
} else {
$seq = 1;
}
return sprintf('%s-%s-%04d', $prefix, $date, $seq);
}
}