feat: [material] 부적합관리 결재 연동 구현

- Migration: approval_id FK 추가
- Model: approval() BelongsTo 관계
- Service: submitForApproval() 결재상신 (결재문서+결재선 생성)
- ApprovalService: 승인→CLOSED, 반려/회수→approval_id 해제
- Controller: POST /{id}/submit-approval 엔드포인트
- Route: submit-approval 라우트 등록
This commit is contained in:
김보곤
2026-03-19 09:03:12 +09:00
parent 847c60b03d
commit 6e50fbd1fa
7 changed files with 210 additions and 0 deletions

View File

@@ -3,6 +3,7 @@
namespace App\Services;
use App\Models\Documents\Document;
use App\Models\Materials\NonconformingReport;
use App\Models\Members\User;
use App\Models\Tenants\Approval;
use App\Models\Tenants\ApprovalDelegation;
@@ -903,6 +904,7 @@ public function approve(int $id, ?string $comment = null): Approval
// Leave 연동 (승인 완료 시)
if ($approval->status === Approval::STATUS_APPROVED) {
$this->handleApprovalCompleted($approval);
$this->handleNonconformingApproved($approval);
}
return $approval->fresh([
@@ -964,6 +966,7 @@ public function reject(int $id, string $comment): Approval
// Leave 연동 (반려 시)
$this->handleApprovalRejected($approval, $comment);
$this->handleNonconformingRejected($approval);
return $approval->fresh([
'form:id,name,code,category',
@@ -1027,6 +1030,7 @@ public function cancel(int $id, ?string $recallReason = null): Approval
// Leave 연동 (회수 시)
$this->handleApprovalCancelled($approval);
$this->handleNonconformingCancelled($approval);
return $approval->fresh([
'form:id,name,code,category',
@@ -1172,6 +1176,7 @@ public function preDecide(int $id, ?string $comment = null): Approval
// Leave 연동 (승인 완료)
$this->handleApprovalCompleted($approval);
$this->handleNonconformingApproved($approval);
return $approval->fresh([
'form:id,name,code,category',
@@ -1732,6 +1737,64 @@ private function createLeaveFromApproval(Approval $approval): Leave
]);
}
// =========================================================================
// 부적합관리 연동
// =========================================================================
/**
* 부적합 결재 승인 시 → CLOSED
*/
private function handleNonconformingApproved(Approval $approval): void
{
if ($approval->linkable_type !== NonconformingReport::class) {
return;
}
$report = NonconformingReport::find($approval->linkable_id);
if ($report && $report->status === NonconformingReport::STATUS_RESOLVED) {
$report->update([
'status' => NonconformingReport::STATUS_CLOSED,
'updated_by' => $approval->updated_by,
]);
}
}
/**
* 부적합 결재 반려 시 → RESOLVED로 유지 (재상신 가능)
*/
private function handleNonconformingRejected(Approval $approval): void
{
if ($approval->linkable_type !== NonconformingReport::class) {
return;
}
$report = NonconformingReport::find($approval->linkable_id);
if ($report) {
$report->update([
'approval_id' => null,
'updated_by' => $approval->updated_by,
]);
}
}
/**
* 부적합 결재 회수 시 → 결재 연결 해제
*/
private function handleNonconformingCancelled(Approval $approval): void
{
if ($approval->linkable_type !== NonconformingReport::class) {
return;
}
$report = NonconformingReport::find($approval->linkable_id);
if ($report) {
$report->update([
'approval_id' => null,
'updated_by' => $approval->updated_by,
]);
}
}
// =========================================================================
// 위임 관리
// =========================================================================