diff --git a/app/Http/Controllers/ProjectClosureController.php b/app/Http/Controllers/ProjectClosureController.php
index a87c3f9..a7ab53f 100644
--- a/app/Http/Controllers/ProjectClosureController.php
+++ b/app/Http/Controllers/ProjectClosureController.php
@@ -17,7 +17,8 @@
class ProjectClosureController extends Controller {
public function closureForm(Project $project): Response {
$this->authorize('update-project', $project);
- abort_if($project->hasSubmittedClosure(), 403, 'Closure already submitted');
+ abort_unless(in_array($project->getClosureStatus(), [ProjectClosureStatus::NOT_SUBMITTED, ProjectClosureStatus::REJECTED_AND_RESUBMIT])
+ , 403, 'Closure already submitted');
$project->load(['department', 'participants', 'participants.user']);
$project->participants->transform(function (ProjectParticipant $participant) {
@@ -42,7 +43,9 @@ public function closureSubmit(Request $request, Project $project) {
'action' => 'nullable|string',
]);
$this->authorize('update-project', $project);
- abort_if($project->hasSubmittedClosure(), 403, 'Closure already submitted.');
+ abort_if($project->hasSubmittedClosure()
+ and $project->getClosureStatus() !== ProjectClosureStatus::REJECTED_AND_RESUBMIT,
+ 403, 'Closure already submitted.');
$action = $request->input('action');
$project->objectives = $request->input('objectives');
@@ -187,7 +190,8 @@ public function approvalSubmit(Request $request, Project $project) {
'approve_participants' => 'nullable|required_if:approve,yes|array',
]);
$closureStatus = $project->getClosureStatus();
- abort_unless(in_array($closureStatus, [ProjectClosureStatus::SUBMITTED, ProjectClosureStatus::REVIEWING]), 403,
+ abort_unless(in_array($closureStatus,
+ [ProjectClosureStatus::SUBMITTED, ProjectClosureStatus::REVIEWING, ProjectClosureStatus::REJECTED_AND_RESUBMIT]), 403,
'Closure approved or hasn\'t been submitted.');
$project->closure_approved_by = $request->user()->id;
@@ -198,6 +202,9 @@ public function approvalSubmit(Request $request, Project $project) {
$project->closure_approved_message = null;
$project->participants()->whereIn('user_id', $request->input('approve_participants'))->update(['approve_status' => 1]);
$project->participants()->whereNotIn('user_id', $request->input('approve_participants'))->update(['approve_status' => -1]);
+ } elseif ($request->input('allow_resubmit', false)) {
+ $project->closure_approved_status = -2;
+ $project->closure_approved_message = $request->input('reason');
} else {
$project->closure_approved_status = -1;
$project->closure_approved_message = $request->input('reason');
diff --git a/app/Http/Controllers/ProjectController.php b/app/Http/Controllers/ProjectController.php
index 9ea9f47..c7b0219 100644
--- a/app/Http/Controllers/ProjectController.php
+++ b/app/Http/Controllers/ProjectController.php
@@ -7,6 +7,7 @@
use App\Models\Project;
use App\Models\ProjectParticipant;
use App\Models\User;
+use App\ProjectClosureStatus;
use Carbon\Carbon;
use Illuminate\Auth\Access\AuthorizationException;
use Illuminate\Contracts\Encryption\DecryptException;
@@ -137,13 +138,18 @@ public function show(Request $request, Project $project) {
return $participant;
});
+ $project->closure_status = $project->getClosureStatus();
$project->shouldBeClosed = (
$canUpdateProject
and $project->created_at->isBetween(now()->subYear(), now()->subWeeks(1))
and $project->documents->isNotEmpty()
and ($project->documents->where('tag', 'summary')->isEmpty() or (!$project->hasSubmittedClosure() and $project->canSubmitClosure()))
);
- $project->shouldVerify = $project->canVerify() and $project->participants->where('user_id', Auth::id())->isNotEmpty();
+ $project->shouldVerify = (
+ $project->canVerify()
+ and $project->participants->where('user_id', Auth::id())->isNotEmpty()
+ and ($project->closure_status != ProjectClosureStatus::REJECTED_AND_RESUBMIT)
+ );
// and !in_array($project->department_id, [32, 38, 39]);
@@ -160,6 +166,12 @@ public function edit(Request $request, Project $project): Response {
$project->organizers = $project->participants()->with('user')->where('type', 'organizer')->get()->map(function (ProjectParticipant $p) {
return ['name' => $p->user->name, 'student_id' => $p->user->student_id];
});
+ $project->closure_status = $project->getClosureStatus();
+
+ // Disable editing if closure is submitted, unless for faculty users
+ abort_if(!in_array($project->closure_status,
+ [ProjectClosureStatus::NOT_SUBMITTED, ProjectClosureStatus::REJECTED_AND_RESUBMIT]) and $request->user()->cannot('faculty-action'),
+ 403, 'Cannot edit after submitted closure.');
return Inertia::render('ProjectCreate', [
'item' => $project->castDateAsDateString(),
@@ -199,7 +211,8 @@ public function update(Request $request, Project $project) {
$this->authorize('update-project', $project);
// Disable editing if closure is submitted, unless for faculty users
- abort_if($project->hasSubmittedClosure() and $request->user()->cannot('faculty-action'),
+ abort_if(!in_array($project->getClosureStatus(),
+ [ProjectClosureStatus::NOT_SUBMITTED, ProjectClosureStatus::REJECTED_AND_RESUBMIT]) and $request->user()->cannot('faculty-action'),
403, 'Cannot edit after submitted closure.');
$project->fill($request->all());
diff --git a/app/Models/Project.php b/app/Models/Project.php
index 39bf64b..986d951 100644
--- a/app/Models/Project.php
+++ b/app/Models/Project.php
@@ -61,6 +61,8 @@ class Project extends Model {
'period_end' => 'date:j M Y',
'objectives' => 'array',
'expense' => 'array',
+ 'closure_submitted_at' => 'datetime',
+ 'closure_approved_at' => 'datetime',
];
protected $hidden = ['user_id'];
@@ -182,7 +184,9 @@ public static function advisorList(): \Illuminate\Support\Collection
* Is the project's period end within the summary time limit?
*/
public function canSubmitClosure(): bool {
- return ($this->period_end->diffInDays() <= self::SUMMARY_TIME_LIMIT) or ($this->year == 2567 and now()->isBefore('2024-09-30'));
+ return ($this->period_end->diffInDays() <= self::SUMMARY_TIME_LIMIT)
+ or ($this->year == 2567 and now()->isBefore('2024-09-30'))
+ or ($this->closure_approved_status == -2 and $this->closure_approved_at->diffInDays() <= self::SUMMARY_TIME_LIMIT);
}
public function hasSubmittedClosure(): bool {
@@ -201,6 +205,10 @@ public function getClosureStatus(): ProjectClosureStatus {
return ProjectClosureStatus::APPROVED;
case -1:
return ProjectClosureStatus::REJECTED;
+ case -2:
+ if ($this->closure_approved_at?->isAfter($this->closure_submitted_at)) {
+ return ProjectClosureStatus::REJECTED_AND_RESUBMIT;
+ }
}
// Count participants who have verified
$organizers = $this->participants->where('type', 'organizer');
@@ -218,7 +226,11 @@ public function getClosureStatus(): ProjectClosureStatus {
}
public function canVerify(): bool {
- return in_array($this->getClosureStatus(), [ProjectClosureStatus::SUBMITTED, ProjectClosureStatus::REVIEWING])
- and ($this->period_end->diffInDays() <= self::VERIFICATION_TIME_LIMIT or ($this->year == 2567 and now()->isBefore('2024-10-31')));
+ return in_array($this->getClosureStatus(),
+ [ProjectClosureStatus::SUBMITTED, ProjectClosureStatus::REVIEWING, ProjectClosureStatus::REJECTED_AND_RESUBMIT])
+ and (($this->period_end->diffInDays() <= self::VERIFICATION_TIME_LIMIT)
+ or ($this->year == 2567 and now()->isBefore('2024-10-31'))
+ or ($this->closure_approved_status == -2 and $this->closure_approved_at->diffInDays() <= self::SUMMARY_TIME_LIMIT)
+ );
}
}
diff --git a/app/ProjectClosureStatus.php b/app/ProjectClosureStatus.php
index 7672f3f..33ad017 100644
--- a/app/ProjectClosureStatus.php
+++ b/app/ProjectClosureStatus.php
@@ -8,4 +8,5 @@ enum ProjectClosureStatus: int {
case REVIEWING = 5;
case APPROVED = 10;
case REJECTED = -1;
+ case REJECTED_AND_RESUBMIT = -2; // Rejected but allow resubmission within the time limit
}
diff --git a/resources/js/Components/ClosureStatusText.vue b/resources/js/Components/ClosureStatusText.vue
new file mode 100644
index 0000000..9f8e42e
--- /dev/null
+++ b/resources/js/Components/ClosureStatusText.vue
@@ -0,0 +1,24 @@
+
+
+
+
+ {{
+ {
+ 0: 'ยังไม่รายงานผล',
+ 1: 'ส่งปิดโครงแล้ว',
+ 5: 'นิสิตผู้เกี่ยวข้องยืนยันแล้ว รอพิจารณา',
+ 10: 'อนุมัติ',
+ '-1': 'ไม่อนุมัติ',
+ '-2': 'ไม่อนุมัติ ให้แก้ไข',
+ }[closure_status] ?? closure_status
+ }}
+
ระบบจะขยายกรอบเวลาในการส่งใหม่ออกไปอีก 30 วัน
+
+