From 8213ee7ee123280fe3d3098230e02cc205472977 Mon Sep 17 00:00:00 2001 From: Kazem Alghasi Date: Wed, 30 Sep 2026 19:01:27 +0330 Subject: [PATCH] fix(shipment): ensure pending review existence during status transitions Add logic to automatically create a pending shipment review if one does not exist when transitioning shipment statuses. This ensures the review lifecycle remains intact for shipments created through paths that bypass initial review generation. Also include migrations to make `user_id` and `status` nullable on `shipment_checklists` to support unassigned or incomplete checklists. --- .../app/Services/ShipmentReviewService.php | 24 +++++++++++++ ...ser_id_nullable_in_shipment_checklists.php | 33 +++++++++++++++++ ...status_nullable_in_shipment_checklists.php | 35 +++++++++++++++++++ 3 files changed, 92 insertions(+) create mode 100644 04_Laravel/database/migrations/2026_09_30_300001_make_user_id_nullable_in_shipment_checklists.php create mode 100644 04_Laravel/database/migrations/2026_09_30_300002_make_status_nullable_in_shipment_checklists.php diff --git a/04_Laravel/app/Services/ShipmentReviewService.php b/04_Laravel/app/Services/ShipmentReviewService.php index aceaf11..2716ff7 100644 --- a/04_Laravel/app/Services/ShipmentReviewService.php +++ b/04_Laravel/app/Services/ShipmentReviewService.php @@ -79,6 +79,9 @@ class ShipmentReviewService 'این سفارش در وضعیت قابل تأیید نیست.' ); + // اگه review pending وجود نداره (سفارش بدون review ایجاد شده)، بساز + $this->ensurePendingReview($shipment); + $review = $this->getPendingReview($shipment); $oldStatus = $shipment->status; @@ -133,6 +136,8 @@ class ShipmentReviewService 'این سفارش در وضعیت قابل رد نیست.' ); + $this->ensurePendingReview($shipment); + $review = $this->getPendingReview($shipment); $oldStatus = $shipment->status; @@ -177,6 +182,25 @@ class ShipmentReviewService } } + /** + * اگه review pending وجود نداره (سفارش از مسیری بدون ساخت review ایجاد شده)، + * revision بعدی با decision=pending می‌سازد تا چرخه تأیید/رد کامل بشه. + */ + private function ensurePendingReview(Shipment $shipment): void + { + $exists = $shipment->reviews() + ->where('decision', ReviewState::Pending->value) + ->exists(); + + if (!$exists) { + ShipmentReview::create([ + 'shipment_id' => $shipment->id, + 'revision_no' => $this->nextReviewRevision($shipment), + 'decision' => ReviewState::Pending->value, + ]); + } + } + /** * پیدا کردن Review فعلی که منتظر تصمیم کارمند است. * diff --git a/04_Laravel/database/migrations/2026_09_30_300001_make_user_id_nullable_in_shipment_checklists.php b/04_Laravel/database/migrations/2026_09_30_300001_make_user_id_nullable_in_shipment_checklists.php new file mode 100644 index 0000000..fa932f4 --- /dev/null +++ b/04_Laravel/database/migrations/2026_09_30_300001_make_user_id_nullable_in_shipment_checklists.php @@ -0,0 +1,33 @@ +getDriverName() === 'sqlite') { + return; + } + + // MODIFY COLUMN روی ستون FK امن است؛ constraint باقی می‌ماند. + DB::statement("ALTER TABLE `shipment_checklists` MODIFY COLUMN `user_id` BIGINT UNSIGNED NULL"); + } + + public function down(): void + { + if (DB::connection()->getDriverName() === 'sqlite') { + return; + } + + $nulls = DB::table('shipment_checklists')->whereNull('user_id')->count(); + if ($nulls === 0) { + DB::statement("ALTER TABLE `shipment_checklists` MODIFY COLUMN `user_id` BIGINT UNSIGNED NOT NULL"); + } + } +}; \ No newline at end of file diff --git a/04_Laravel/database/migrations/2026_09_30_300002_make_status_nullable_in_shipment_checklists.php b/04_Laravel/database/migrations/2026_09_30_300002_make_status_nullable_in_shipment_checklists.php new file mode 100644 index 0000000..fc88a96 --- /dev/null +++ b/04_Laravel/database/migrations/2026_09_30_300002_make_status_nullable_in_shipment_checklists.php @@ -0,0 +1,35 @@ +getDriverName() === 'sqlite') { + return; + } + + DB::statement("ALTER TABLE `shipment_checklists` MODIFY COLUMN `status` VARCHAR(255) NULL"); + } + + public function down(): void + { + if (DB::connection()->getDriverName() === 'sqlite') { + return; + } + + $nulls = DB::table('shipment_checklists')->whereNull('status')->count(); + if ($nulls === 0) { + DB::statement("ALTER TABLE `shipment_checklists` MODIFY COLUMN `status` VARCHAR(255) NOT NULL"); + } else { + DB::table('shipment_checklists')->whereNull('status')->update(['status' => 'pending']); + DB::statement("ALTER TABLE `shipment_checklists` MODIFY COLUMN `status` VARCHAR(255) NOT NULL"); + } + } +}; \ No newline at end of file