From 9cfb566aee38ca49dbca10cdae70907ec0aa1c70 Mon Sep 17 00:00:00 2001 From: arifal Date: Sun, 15 Jun 2025 02:29:26 +0700 Subject: [PATCH] remove status pending and complete --- app/Console/Commands/CleanMutationsData.php | 97 +++++ app/Enums/MutationStatus.php | 10 +- .../MutationsController.php | 113 +++-- app/Models/Mutation.php | 85 ++-- app/Models/MutationDetail.php | 10 +- ...tion_details_quantity_approved_default.php | 2 +- ...nd_rejection_fields_to_mutations_table.php | 3 + ...ng_and_completed_from_mutations_status.php | 36 ++ ..._06_15_015235_manual_cleanup_mutations.php | 50 +++ database/seeders/MutationTestSeeder.php | 14 +- resources/views/transaction/index.blade.php | 389 +++++++++++++++--- .../mutations/_action.blade.php | 50 +-- .../mutations/show.blade.php | 43 +- 13 files changed, 666 insertions(+), 236 deletions(-) create mode 100644 app/Console/Commands/CleanMutationsData.php create mode 100644 database/migrations/2025_06_15_015234_remove_pending_and_completed_from_mutations_status.php create mode 100644 database/migrations/2025_06_15_015235_manual_cleanup_mutations.php diff --git a/app/Console/Commands/CleanMutationsData.php b/app/Console/Commands/CleanMutationsData.php new file mode 100644 index 0000000..b6e71f2 --- /dev/null +++ b/app/Console/Commands/CleanMutationsData.php @@ -0,0 +1,97 @@ +option('force')) { + if (!$this->confirm('This will delete ALL mutations data. Are you sure?')) { + $this->info('Operation cancelled.'); + return 0; + } + } + + try { + DB::beginTransaction(); + + // Delete mutations data in proper order (foreign key constraints) + $this->info('Cleaning mutations data...'); + + // 1. Delete stock logs related to mutations + if (Schema::hasTable('stock_logs')) { + $deleted = DB::table('stock_logs') + ->where('source_type', 'App\\Models\\Mutation') + ->delete(); + $this->info("Deleted {$deleted} stock logs related to mutations"); + } + + // 2. Delete mutation details + if (Schema::hasTable('mutation_details')) { + $deleted = DB::table('mutation_details')->delete(); + $this->info("Deleted {$deleted} mutation details"); + } + + // 3. Delete mutations + if (Schema::hasTable('mutations')) { + $deleted = DB::table('mutations')->delete(); + $this->info("Deleted {$deleted} mutations"); + } + + // 4. Reset auto increment + if (Schema::hasTable('mutations')) { + DB::statement('ALTER TABLE mutations AUTO_INCREMENT = 1'); + $this->info('Reset mutations auto increment'); + } + + if (Schema::hasTable('mutation_details')) { + DB::statement('ALTER TABLE mutation_details AUTO_INCREMENT = 1'); + $this->info('Reset mutation_details auto increment'); + } + + DB::commit(); + + $this->info('✅ Mutations data cleaned successfully!'); + $this->info('You can now rollback and re-run migrations.'); + + return 0; + + } catch (\Exception $e) { + DB::rollback(); + $this->error('❌ Error cleaning mutations data: ' . $e->getMessage()); + return 1; + } + } +} diff --git a/app/Enums/MutationStatus.php b/app/Enums/MutationStatus.php index 073d5d7..c5771e9 100755 --- a/app/Enums/MutationStatus.php +++ b/app/Enums/MutationStatus.php @@ -4,23 +4,19 @@ namespace App\Enums; enum MutationStatus: string { - case PENDING = 'pending'; case SENT = 'sent'; case RECEIVED = 'received'; case APPROVED = 'approved'; case REJECTED = 'rejected'; - case COMPLETED = 'completed'; case CANCELLED = 'cancelled'; public function label(): string { return match($this) { - self::PENDING => 'Menunggu Konfirmasi', self::SENT => 'Terkirim ke Dealer', self::RECEIVED => 'Diterima Dealer', - self::APPROVED => 'Disetujui', + self::APPROVED => 'Disetujui & Stock Dipindahkan', self::REJECTED => 'Ditolak', - self::COMPLETED => 'Selesai', self::CANCELLED => 'Dibatalkan', }; } @@ -28,12 +24,10 @@ enum MutationStatus: string public function color(): string { return match($this) { - self::PENDING => 'warning', self::SENT => 'primary', self::RECEIVED => 'info', self::APPROVED => 'brand', self::REJECTED => 'danger', - self::COMPLETED => 'success', self::CANCELLED => 'secondary', }; } @@ -55,12 +49,10 @@ enum MutationStatus: string public static function getOptions(): array { return [ - self::PENDING->value => self::PENDING->label(), self::SENT->value => self::SENT->label(), self::RECEIVED->value => self::RECEIVED->label(), self::APPROVED->value => self::APPROVED->label(), self::REJECTED->value => self::REJECTED->label(), - self::COMPLETED->value => self::COMPLETED->label(), self::CANCELLED->value => self::CANCELLED->label(), ]; } diff --git a/app/Http/Controllers/WarehouseManagement/MutationsController.php b/app/Http/Controllers/WarehouseManagement/MutationsController.php index 249aecf..743a8f7 100755 --- a/app/Http/Controllers/WarehouseManagement/MutationsController.php +++ b/app/Http/Controllers/WarehouseManagement/MutationsController.php @@ -182,8 +182,18 @@ class MutationsController extends Controller $mutation->receive(auth()->id(), $request->reception_notes); DB::commit(); - return redirect()->route('mutations.index') - ->with('success', 'Mutasi berhasil diterima dan menunggu persetujuan pengirim'); + + // Check user role and redirect accordingly + if (!auth()->user()->dealer_id) { + // Users without dealer_id are likely admin, redirect to mutations index + return redirect()->route('mutations.index') + ->with('success', 'Mutasi berhasil diterima dan siap untuk disetujui. Stock akan dipindahkan setelah disetujui.'); + } else { + // Dealer users redirect back to transaction page + return redirect()->route('transaction') + ->with('success', 'Mutasi berhasil diterima. Silakan setujui mutasi ini untuk memindahkan stock.') + ->with('active_tab', 'penerimaan'); + } } catch (\Exception $e) { DB::rollback(); @@ -202,11 +212,25 @@ class MutationsController extends Controller } try { - // Approve mutation (quantity_approved sudah diisi saat receive) + // Approve mutation (stock will move automatically) $mutation->approve(auth()->id(), $request->approval_notes); - return redirect()->route('mutations.index') - ->with('success', 'Mutasi berhasil disetujui'); + // Check user role and redirect accordingly + if (!auth()->user()->dealer_id) { + // Admin users redirect to mutations index + return redirect()->route('mutations.index') + ->with('success', 'Mutasi berhasil disetujui dan stock telah dipindahkan'); + } else { + // Dealer users + if ($request->has('from_transaction_page') || str_contains($request->header('referer', ''), '/transaction')) { + return redirect()->route('transaction') + ->with('success', 'Mutasi berhasil disetujui dan stock telah dipindahkan') + ->with('active_tab', 'penerimaan'); + } else { + return redirect()->route('mutations.index') + ->with('success', 'Mutasi berhasil disetujui dan stock telah dipindahkan'); + } + } } catch (\Exception $e) { return back()->withErrors(['error' => 'Gagal menyetujui mutasi: ' . $e->getMessage()]); @@ -226,30 +250,29 @@ class MutationsController extends Controller try { $mutation->reject(auth()->id(), $request->rejection_reason); - return redirect()->route('mutations.index') - ->with('success', 'Mutasi berhasil ditolak'); + // Check user role and redirect accordingly + if (!auth()->user()->dealer_id) { + // Admin users redirect to mutations index + return redirect()->route('mutations.index') + ->with('success', 'Mutasi berhasil ditolak'); + } else { + // Dealer users + if ($request->has('from_transaction_page') || str_contains($request->header('referer', ''), '/transaction')) { + return redirect()->route('transaction') + ->with('success', 'Mutasi berhasil ditolak') + ->with('active_tab', 'penerimaan'); + } else { + return redirect()->route('mutations.index') + ->with('success', 'Mutasi berhasil ditolak'); + } + } } catch (\Exception $e) { return back()->withErrors(['error' => 'Gagal menolak mutasi: ' . $e->getMessage()]); } } - public function complete(Mutation $mutation) - { - if (!$mutation->canBeCompleted()) { - return back()->withErrors(['error' => 'Mutasi tidak dapat diselesaikan dalam status saat ini']); - } - - try { - $mutation->complete(); - - return redirect()->route('mutations.index') - ->with('success', 'Mutasi berhasil diselesaikan dan stock telah dipindahkan'); - - } catch (\Exception $e) { - return back()->withErrors(['error' => 'Gagal menyelesaikan mutasi: ' . $e->getMessage()]); - } - } + // Complete method removed - Stock moves automatically after approval public function cancel(Request $request, Mutation $mutation) { @@ -294,9 +317,20 @@ class MutationsController extends Controller { $dealerId = $request->dealer_id; + // Get mutations that need action from this dealer: + // 1. 'sent' status where this dealer is the recipient (need to receive) + // 2. 'received' status where this dealer is the recipient (need to approve) - CORRECTED LOGIC $data = Mutation::with(['fromDealer', 'toDealer', 'requestedBy.role']) - ->where('to_dealer_id', $dealerId) - ->where('status', 'sent') + ->where(function($query) use ($dealerId) { + // Mutations sent to this dealer that need to be received + $query->where('to_dealer_id', $dealerId) + ->where('status', 'sent'); + // OR mutations received by this dealer that need approval from recipient + $query->orWhere(function($subQuery) use ($dealerId) { + $subQuery->where('to_dealer_id', $dealerId) + ->where('status', 'received'); + }); + }) ->select('mutations.*'); return DataTables::of($data) @@ -307,6 +341,9 @@ class MutationsController extends Controller ->addColumn('from_dealer', function($row) { return $row->fromDealer->name ?? '-'; }) + ->addColumn('to_dealer', function($row) { + return $row->toDealer->name ?? '-'; + }) ->addColumn('status', function($row) { $statusColor = $row->status_color; $statusLabel = $row->status_label; @@ -330,10 +367,28 @@ class MutationsController extends Controller ->addColumn('created_at', function($row) { return $row->created_at->format('d/m/Y H:i'); }) - ->addColumn('action', function($row) { - return ''; + ->addColumn('action', function($row) use ($dealerId) { + $buttons = ''; + + if ($row->status->value === 'sent' && $row->to_dealer_id == $dealerId) { + // For sent mutations where current dealer is recipient - show detail button for receiving + $buttons .= ''; + } elseif ($row->status->value === 'received' && $row->to_dealer_id == $dealerId) { + // For received mutations where current dealer is recipient - show approve/reject buttons + $buttons .= ''; + $buttons .= ''; + $buttons .= ''; + } + + return $buttons; }) ->rawColumns(['status', 'action']) ->make(true); diff --git a/app/Models/Mutation.php b/app/Models/Mutation.php index 40e7498..5a8c70e 100755 --- a/app/Models/Mutation.php +++ b/app/Models/Mutation.php @@ -116,11 +116,6 @@ class Mutation extends Model return $this->mutationDetails()->sum('quantity_approved'); } - public function canBeSent() - { - return $this->status === MutationStatus::PENDING; - } - public function canBeReceived() { return $this->status === MutationStatus::SENT; @@ -131,28 +126,9 @@ class Mutation extends Model return $this->status === MutationStatus::RECEIVED; } - public function canBeCompleted() - { - return $this->status === MutationStatus::APPROVED; - } - public function canBeCancelled() { - return in_array($this->status, [MutationStatus::PENDING, MutationStatus::SENT]); - } - - // Send mutation to destination dealer - public function send($userId) - { - if (!$this->canBeSent()) { - throw new \Exception('Mutasi tidak dapat dikirim dalam status saat ini'); - } - - $this->update([ - 'status' => MutationStatus::SENT - ]); - - return $this; + return $this->status === MutationStatus::SENT; } // Receive mutation by destination dealer @@ -172,19 +148,37 @@ class Mutation extends Model return $this; } - // Approve mutation + // Approve mutation and move stock immediately public function approve($userId, $approvalNotes = null) { if (!$this->canBeApproved()) { throw new \Exception('Mutasi tidak dapat disetujui dalam status saat ini'); } - $this->update([ - 'status' => MutationStatus::APPROVED, - 'approved_by' => $userId, - 'approved_at' => now(), - 'approval_notes' => $approvalNotes - ]); + DB::beginTransaction(); + try { + // Update status to approved first + $this->update([ + 'status' => MutationStatus::APPROVED, + 'approved_by' => $userId, + 'approved_at' => now(), + 'approval_notes' => $approvalNotes + ]); + + // Immediately move stock after approval + foreach ($this->mutationDetails as $detail) { + // Process all details that have quantity_requested > 0 + // because goods have been sent from source dealer + if ($detail->quantity_requested > 0) { + $this->processStockMovement($detail); + } + } + + DB::commit(); + } catch (\Exception $e) { + DB::rollback(); + throw $e; + } return $this; } @@ -223,32 +217,7 @@ class Mutation extends Model return $this; } - // Complete mutation (actually move the stock) - public function complete() - { - if (!$this->canBeCompleted()) { - throw new \Exception('Mutasi tidak dapat diselesaikan dalam status saat ini'); - } - - DB::beginTransaction(); - try { - foreach ($this->mutationDetails as $detail) { - // Proses semua detail yang memiliki quantity_requested > 0 - // karena barang sudah dikirim dari dealer asal - if ($detail->quantity_requested > 0) { - $this->processStockMovement($detail); - } - } - - $this->update(['status' => MutationStatus::COMPLETED]); - DB::commit(); - } catch (\Exception $e) { - DB::rollback(); - throw $e; - } - - return $this; - } + // Complete method removed - Stock moves automatically after approval private function processStockMovement(MutationDetail $detail) { diff --git a/app/Models/MutationDetail.php b/app/Models/MutationDetail.php index 0138c6d..15f91c9 100755 --- a/app/Models/MutationDetail.php +++ b/app/Models/MutationDetail.php @@ -52,7 +52,7 @@ class MutationDetail extends Model { // Hanya dianggap ditolak jika mutasi sudah di-approve/reject dan quantity_approved = 0 $mutationStatus = $this->mutation->status->value ?? null; - return in_array($mutationStatus, ['approved', 'completed', 'rejected']) && $this->quantity_approved == 0; + return in_array($mutationStatus, ['approved', 'rejected']) && $this->quantity_approved == 0; } public function getApprovalStatusAttribute() @@ -60,11 +60,11 @@ class MutationDetail extends Model $mutationStatus = $this->mutation->status->value ?? null; // Jika mutasi belum di-approve, semua detail statusnya "Menunggu" - if (!in_array($mutationStatus, ['approved', 'completed', 'rejected'])) { + if (!in_array($mutationStatus, ['approved', 'rejected'])) { return 'Menunggu'; } - // Jika mutasi sudah di-approve/complete, baru cek quantity_approved + // Jika mutasi sudah di-approve, baru cek quantity_approved if ($this->isFullyApproved()) { return 'Disetujui Penuh'; } elseif ($this->isPartiallyApproved()) { @@ -81,11 +81,11 @@ class MutationDetail extends Model $mutationStatus = $this->mutation->status->value ?? null; // Jika mutasi belum di-approve, semua detail statusnya "info" (menunggu) - if (!in_array($mutationStatus, ['approved', 'completed', 'rejected'])) { + if (!in_array($mutationStatus, ['approved', 'rejected'])) { return 'info'; } - // Jika mutasi sudah di-approve/complete, baru cek quantity_approved + // Jika mutasi sudah di-approve, baru cek quantity_approved if ($this->isFullyApproved()) { return 'success'; } elseif ($this->isPartiallyApproved()) { diff --git a/database/migrations/2025_06_12_111500_update_mutation_details_quantity_approved_default.php b/database/migrations/2025_06_12_111500_update_mutation_details_quantity_approved_default.php index 9c2f9cc..f2bc89c 100755 --- a/database/migrations/2025_06_12_111500_update_mutation_details_quantity_approved_default.php +++ b/database/migrations/2025_06_12_111500_update_mutation_details_quantity_approved_default.php @@ -16,7 +16,7 @@ return new class extends Migration DB::table('mutation_details') ->join('mutations', 'mutations.id', '=', 'mutation_details.mutation_id') ->where('mutation_details.quantity_approved', 0) - ->whereNotIn('mutations.status', ['approved', 'completed', 'rejected']) + ->whereNotIn('mutations.status', ['approved', 'rejected']) ->update(['mutation_details.quantity_approved' => null]); Schema::table('mutation_details', function (Blueprint $table) { diff --git a/database/migrations/2025_06_13_130135_add_additional_notes_and_rejection_fields_to_mutations_table.php b/database/migrations/2025_06_13_130135_add_additional_notes_and_rejection_fields_to_mutations_table.php index b25acfa..32785d1 100755 --- a/database/migrations/2025_06_13_130135_add_additional_notes_and_rejection_fields_to_mutations_table.php +++ b/database/migrations/2025_06_13_130135_add_additional_notes_and_rejection_fields_to_mutations_table.php @@ -40,6 +40,9 @@ class AddAdditionalNotesAndRejectionFieldsToMutationsTable extends Migration public function down() { Schema::table('mutations', function (Blueprint $table) { + $table->dropForeign(['rejected_by']); + $table->dropForeign(['cancelled_by']); + // Remove new fields $table->dropColumn([ 'reception_notes', diff --git a/database/migrations/2025_06_15_015234_remove_pending_and_completed_from_mutations_status.php b/database/migrations/2025_06_15_015234_remove_pending_and_completed_from_mutations_status.php new file mode 100644 index 0000000..cd257a0 --- /dev/null +++ b/database/migrations/2025_06_15_015234_remove_pending_and_completed_from_mutations_status.php @@ -0,0 +1,36 @@ +where('status', 'pending') + ->update(['status' => 'sent']); + + DB::table('mutations') + ->where('status', 'completed') + ->update(['status' => 'approved']); + + // Then update the enum column to remove 'pending' and 'completed' + DB::statement("ALTER TABLE mutations MODIFY COLUMN status ENUM('sent', 'received', 'approved', 'rejected', 'cancelled') DEFAULT 'sent'"); + } + + /** + * Reverse the migrations. + */ + public function down(): void + { + // Restore the original enum with 'pending' and 'completed' + DB::statement("ALTER TABLE mutations MODIFY COLUMN status ENUM('pending', 'sent', 'received', 'approved', 'rejected', 'completed', 'cancelled') DEFAULT 'sent'"); + } +}; diff --git a/database/migrations/2025_06_15_015235_manual_cleanup_mutations.php b/database/migrations/2025_06_15_015235_manual_cleanup_mutations.php new file mode 100644 index 0000000..d81563b --- /dev/null +++ b/database/migrations/2025_06_15_015235_manual_cleanup_mutations.php @@ -0,0 +1,50 @@ +where('status', 'pending') + ->update(['status' => 'sent']); + + // Update existing 'completed' status to 'approved' + DB::table('mutations') + ->where('status', 'completed') + ->update(['status' => 'approved']); + + // Update the enum to only include valid statuses + DB::statement("ALTER TABLE mutations MODIFY COLUMN status ENUM('sent', 'received', 'approved', 'rejected', 'cancelled') DEFAULT 'sent'"); + + // Update any orphaned mutation_details that reference completed status + DB::statement(" + UPDATE mutation_details md + JOIN mutations m ON md.mutation_id = m.id + SET md.quantity_approved = md.quantity_requested + WHERE m.status = 'approved' AND md.quantity_approved IS NULL + "); + } + + /** + * Reverse the migrations. + */ + public function down(): void + { + // Restore original enum (if needed) + DB::statement("ALTER TABLE mutations MODIFY COLUMN status ENUM('pending', 'sent', 'received', 'approved', 'rejected', 'completed', 'cancelled') DEFAULT 'sent'"); + } +}; \ No newline at end of file diff --git a/database/seeders/MutationTestSeeder.php b/database/seeders/MutationTestSeeder.php index e573498..d23920f 100755 --- a/database/seeders/MutationTestSeeder.php +++ b/database/seeders/MutationTestSeeder.php @@ -99,18 +99,18 @@ class MutationTestSeeder extends Seeder 'notes' => 'Produk approved parsial' ]); - // 4. Mutation dengan status COMPLETED (selesai) - $this->command->info('Creating COMPLETED mutation...'); + // 4. Additional APPROVED mutation (completed workflow is now just approved) + $this->command->info('Creating additional APPROVED mutation...'); $mutation4 = Mutation::create([ 'from_dealer_id' => $dealers[0]->id, 'to_dealer_id' => $dealers[1]->id, - 'status' => MutationStatus::COMPLETED, + 'status' => MutationStatus::APPROVED, 'requested_by' => $users[0]->id, 'received_by' => $users[1]->id ?? $users[0]->id, 'received_at' => now()->subDay(), 'approved_by' => $users[0]->id, 'approved_at' => now()->subHours(6), - 'notes' => 'Mutasi test - status COMPLETED' + 'notes' => 'Mutasi test - status APPROVED (stock moved)' ]); MutationDetail::create([ @@ -118,7 +118,7 @@ class MutationTestSeeder extends Seeder 'product_id' => $products[1]->id, 'quantity_requested' => 6.00, 'quantity_approved' => 6.00, - 'notes' => 'Produk completed' + 'notes' => 'Produk approved & stock moved' ]); // 5. Mutation dengan status REJECTED @@ -147,8 +147,8 @@ class MutationTestSeeder extends Seeder $this->command->info('Test mutations created successfully!'); $this->command->info('- Mutation SENT: ' . $mutation1->mutation_number); $this->command->info('- Mutation RECEIVED: ' . $mutation2->mutation_number); - $this->command->info('- Mutation APPROVED: ' . $mutation3->mutation_number); - $this->command->info('- Mutation COMPLETED: ' . $mutation4->mutation_number); + $this->command->info('- Mutation APPROVED (1): ' . $mutation3->mutation_number); + $this->command->info('- Mutation APPROVED (2): ' . $mutation4->mutation_number); $this->command->info('- Mutation REJECTED: ' . $mutation5->mutation_number); } catch (\Exception $e) { diff --git a/resources/views/transaction/index.blade.php b/resources/views/transaction/index.blade.php index e785df2..00a51ad 100755 --- a/resources/views/transaction/index.blade.php +++ b/resources/views/transaction/index.blade.php @@ -164,6 +164,24 @@ use Illuminate\Support\Facades\Auth; .mutation-detail-table input { font-size: 14px; } + + .bg-warning-light { + background-color: #fff3cd !important; + border: 1px solid #ffeaa7; + } + + .form-control-plaintext.border { + background-color: #f8f9fa; + font-style: normal; + } + + .alert ul { + padding-left: 1.2rem; + } + + .alert ul li { + margin-bottom: 0.25rem; + } @endsection @@ -718,16 +736,17 @@ use Illuminate\Support\Facades\Auth;
-
Daftar Mutasi yang Perlu Diterima
+
Daftar Mutasi yang Perlu Diterima & Disetujui
- - - - - + + + + + + @@ -764,6 +783,7 @@ use Illuminate\Support\Facades\Auth; @csrf + @@ -1385,6 +1415,38 @@ use Illuminate\Support\Facades\Auth; $("#btn-save-mutasi").attr("disabled", false); $("#btn-save-mutasi").removeClass("disabled"); $("#btn-save-mutasi").html('Kirim Mutasi'); + } else if (successMessage.toLowerCase().includes('penerimaan') || (successMessage.toLowerCase().includes('mutasi') && successMessage.toLowerCase().includes('diterima')) || activeTab === 'penerimaan') { + // For penerimaan mutasi, just refresh the table without resetting form + // Activate the correct tab first + $('.nav-link[href="#stock"]').tab('show'); + setTimeout(function() { + $('.nav-link[href="#penerimaan"]').tab('show'); + // Stay on penerimaan tab and refresh table + setTimeout(function() { + if (receiveMutationsTable && $.fn.DataTable.isDataTable('#receiveMutationsTable')) { + receiveMutationsTable.ajax.reload(null, false); // Don't reset paging + } else { + // Initialize table if not already initialized + initReceiveMutationsTable(); + } + }, 300); + }, 100); + // Close any open modals + $('#mutationDetailModal').modal('hide'); + } else if (successMessage.toLowerCase().includes('disetujui') || successMessage.toLowerCase().includes('ditolak') || activeTab === 'persetujuan') { + // For approval/rejection, refresh the table + $('.nav-link[href="#stock"]').tab('show'); + setTimeout(function() { + $('.nav-link[href="#penerimaan"]').tab('show'); + // Refresh table to show updated status + setTimeout(function() { + if (receiveMutationsTable && $.fn.DataTable.isDataTable('#receiveMutationsTable')) { + receiveMutationsTable.ajax.reload(null, false); + } else { + initReceiveMutationsTable(); + } + }, 300); + }, 100); } else if (successMessage.toLowerCase().includes('opname') || activeTab === 'opname') { // Reset opname form after success $('#opnameForm')[0].reset(); @@ -1645,6 +1707,7 @@ use Illuminate\Support\Facades\Auth; columns: [ {data: 'mutation_number', name: 'mutation_number'}, {data: 'from_dealer', name: 'from_dealer'}, + {data: 'to_dealer', name: 'to_dealer'}, {data: 'status', name: 'status', orderable: false}, {data: 'total_items', name: 'total_items'}, {data: 'created_at', name: 'created_at'}, @@ -1656,6 +1719,8 @@ use Illuminate\Support\Facades\Auth; }); } + // Function removed since we use single table for both receive and approval mutations + // Show mutation detail modal function showMutationDetail(mutationId) { $('#mutationDetailModal').modal('show'); @@ -1698,6 +1763,8 @@ use Illuminate\Support\Facades\Auth; function renderMutationDetail(mutation) { var statusColor = mutation.status_color; var statusLabel = mutation.status_label; + var isReceived = mutation.status.value === 'received'; + var canBeReceived = mutation.can_be_received; // Set form action URL $('#receiveMutationForm').attr('action', '{{ route("mutations.receive", ":id") }}'.replace(':id', mutation.id)); @@ -1735,13 +1802,6 @@ use Illuminate\Support\Facades\Auth;
-
-
- - -
-
-
Detail Produk & Penerimaan:
No. MutasiDealer AsalStatusTotal ItemTanggalNo. MutasiDealer AsalDealer TujuanStatusTotal ItemTanggal Aksi
@@ -1756,9 +1816,12 @@ use Illuminate\Support\Facades\Auth; `; - // Add product details with form inputs + // Add product details with form inputs or read-only display if (mutation.mutation_details && mutation.mutation_details.length > 0) { mutation.mutation_details.forEach(function(detail) { + var quantityValue = detail.quantity_approved || detail.quantity_requested; + var notesValue = detail.notes || ''; + detailHtml += ` @@ -1766,21 +1829,53 @@ use Illuminate\Support\Facades\Auth; ${parseFloat(detail.quantity_requested).toFixed(2)} `; @@ -1798,21 +1893,76 @@ use Illuminate\Support\Facades\Auth;
${detail.product.name} - + `; + + if (canBeReceived && !isReceived) { + // Editable input for mutations that can be received + detailHtml += ` + + `; + } else { + // Read-only display for received mutations + detailHtml += ` + + ${parseFloat(quantityValue).toFixed(2)} + + ${quantityValue != detail.quantity_requested ? + '(Sebagian)' : ''} + `; + } + + detailHtml += ` - + `; + + if (canBeReceived && !isReceived) { + // Editable textarea for mutations that can be received + detailHtml += ` + + `; + } else { + // Read-only display for received mutations + detailHtml += ` + ${notesValue || '-'} + `; + } + + detailHtml += `
-
- - Petunjuk: - Masukkan quantity yang disetujui untuk setiap produk. Quantity tidak boleh melebihi quantity yang diminta. +
+
+ + `; + + if (canBeReceived && !isReceived) { + // Editable textarea for mutations that can be received + detailHtml += ` + + `; + } else { + // Read-only display for received mutations + detailHtml += ` +
+ ${mutation.reception_notes || 'Tidak ada catatan'} +
+ `; + } + + detailHtml += ` +
`; - $('#mutationDetailContent').html(detailHtml); - - // Show receive button if mutation can be received - if (mutation.can_be_received) { - $('#receiveButton').show(); + // Add instructions based on status + if (canBeReceived && !isReceived) { + detailHtml += ` +
+
+ +
+ Instruksi Penerimaan: +
    +
  • Periksa kondisi fisik produk yang diterima
  • +
  • Masukkan quantity yang benar-benar diterima untuk setiap produk
  • +
  • Quantity yang disetujui tidak boleh melebihi quantity yang diminta
  • +
  • Berikan catatan jika ada produk yang rusak atau tidak sesuai
  • +
+
+ Perhatian: Setelah diterima, catatan tidak dapat diubah lagi. Pastikan informasi sudah benar sebelum menerima mutasi. +
+
+
+
+ `; + } else if (isReceived) { + detailHtml += ` +
+
+ +
+ Status: Mutasi telah diterima dan siap untuk disetujui. +
Stock akan dipindahkan setelah Anda menyetujui mutasi ini. +
+
+
+ `; } - // Add validation for quantity inputs + $('#mutationDetailContent').html(detailHtml); + + // Show receive button only if mutation can be received + if (canBeReceived && !isReceived) { + $('#receiveButton').show(); + } else { + $('#receiveButton').hide(); + } + + // Add validation for quantity inputs (only for editable fields) $('.quantity-approved-input').on('input', function() { var value = parseFloat($(this).val()) || 0; var max = parseFloat($(this).data('max')) || 0; @@ -1864,16 +2014,31 @@ use Illuminate\Support\Facades\Auth; if (typeof Swal !== 'undefined') { Swal.fire({ - title: 'Terima Mutasi?', - text: "Mutasi akan diterima dengan quantity dan catatan yang telah Anda masukkan", - type: 'question', + title: 'Konfirmasi Penerimaan Mutasi', + html: ` +
+

Dengan menerima mutasi ini:

+
    +
  • Anda mengkonfirmasi telah menerima produk dari dealer pengirim
  • +
  • Data quantity dan catatan yang dimasukkan akan disimpan
  • +
  • Mutasi akan masuk ke tahap persetujuan untuk memindahkan stock
  • +
  • Catatan dan data penerimaan tidak dapat diubah setelah diterima
  • +
+
+ + Info: Pastikan semua data sudah benar sebelum menerima mutasi. +
+
+ `, + icon: 'question', showCancelButton: true, confirmButtonColor: '#28a745', cancelButtonColor: '#6c757d', - confirmButtonText: 'Ya, Terima', - cancelButtonText: 'Batal' + confirmButtonText: 'Ya, Terima Mutasi', + cancelButtonText: 'Batal', + width: '500px' }).then((result) => { - if (result.value) { + if (result.isConfirmed) { // Set loading state $('#receiveButton').prop('disabled', true).html(' Memproses...'); @@ -1896,6 +2061,138 @@ use Illuminate\Support\Facades\Auth; }, 100); }); + + + // Handle approve button click + $(document).on('click', '.btn-approve-mutation', function() { + var mutationId = $(this).data('id'); + + Swal.fire({ + title: 'Konfirmasi Persetujuan Mutasi', + html: ` +
+

Dengan menyetujui mutasi ini:

+
    +
  • Stock akan dipindahkan secara otomatis dari dealer asal ke dealer tujuan
  • +
  • Proses mutasi akan selesai dan tidak dapat dibatalkan
  • +
  • Perubahan stock akan tercatat dalam log sistem
  • +
+
+ + +
+
+ `, + icon: 'question', + showCancelButton: true, + confirmButtonColor: '#28a745', + cancelButtonColor: '#6c757d', + confirmButtonText: 'Ya, Setujui Mutasi', + cancelButtonText: 'Batal', + width: '500px', + preConfirm: () => { + return document.getElementById('approval-notes').value; + } + }).then((result) => { + if (result.isConfirmed) { + // Create form and submit + var form = $('
').attr({ + method: 'POST', + action: '{{ route("mutations.approve", ":id") }}'.replace(':id', mutationId) + }); + + form.append($('').attr({ + type: 'hidden', + name: '_token', + value: $('meta[name="csrf-token"]').attr('content') + })); + + form.append($('').attr({ + type: 'hidden', + name: 'from_transaction_page', + value: '1' + })); + + if (result.value) { + form.append($('').attr({ + type: 'hidden', + name: 'approval_notes', + value: result.value + })); + } + + $('body').append(form); + form.submit(); + } + }); + }); + + // Handle reject button click + $(document).on('click', '.btn-reject-mutation', function() { + var mutationId = $(this).data('id'); + + Swal.fire({ + title: 'Konfirmasi Penolakan Mutasi', + html: ` +
+
+ + Perhatian: Mutasi yang ditolak tidak dapat diubah lagi dan proses akan dihentikan. +
+
+ + + Alasan penolakan wajib diisi untuk dokumentasi. +
+
+ `, + icon: 'warning', + showCancelButton: true, + confirmButtonColor: '#dc3545', + cancelButtonColor: '#6c757d', + confirmButtonText: 'Ya, Tolak Mutasi', + cancelButtonText: 'Batal', + width: '500px', + preConfirm: () => { + const reason = document.getElementById('rejection-reason').value; + if (!reason || reason.trim() === '') { + Swal.showValidationMessage('Alasan penolakan harus diisi!'); + return false; + } + return reason; + } + }).then((result) => { + if (result.isConfirmed && result.value) { + // Create form and submit + var form = $('').attr({ + method: 'POST', + action: '{{ route("mutations.reject", ":id") }}'.replace(':id', mutationId) + }); + + form.append($('').attr({ + type: 'hidden', + name: '_token', + value: $('meta[name="csrf-token"]').attr('content') + })); + + form.append($('').attr({ + type: 'hidden', + name: 'from_transaction_page', + value: '1' + })); + + form.append($('').attr({ + type: 'hidden', + name: 'rejection_reason', + value: result.value + })); + + $('body').append(form); + form.submit(); + } + }); + }); + // Save active tab to localStorage $('.nav-link').on('click', function() { var target = $(this).attr('href'); diff --git a/resources/views/warehouse_management/mutations/_action.blade.php b/resources/views/warehouse_management/mutations/_action.blade.php index ddc76ce..33a88ec 100755 --- a/resources/views/warehouse_management/mutations/_action.blade.php +++ b/resources/views/warehouse_management/mutations/_action.blade.php @@ -52,25 +52,8 @@ @endif @if($row->status->value === 'approved') - - @can('complete-mutation') - - @endcan - - - @can('edit-mutation') - - @endcan + + Stock Telah Dipindahkan @endif
@@ -86,6 +69,7 @@ -

Setelah menerima, mutasi akan menunggu persetujuan dari pengirim sebelum stock dipindahkan.

+

Setelah menerima, mutasi akan menunggu persetujuan dari pengirim. Stock akan dipindahkan otomatis setelah disetujui.

- - \ No newline at end of file + \ No newline at end of file diff --git a/resources/views/warehouse_management/mutations/show.blade.php b/resources/views/warehouse_management/mutations/show.blade.php index 2ffe609..009a123 100755 --- a/resources/views/warehouse_management/mutations/show.blade.php +++ b/resources/views/warehouse_management/mutations/show.blade.php @@ -158,7 +158,7 @@ {{ $detail->product->name }} {{ number_format($detail->quantity_requested, 2) }} - @if($mutation->status->value === 'received' || $mutation->status->value === 'approved' || $mutation->status->value === 'completed') + @if($mutation->status->value === 'received' || $mutation->status->value === 'approved') {{ number_format($detail->quantity_approved ?? 0, 2) }} @else Belum ditentukan @@ -187,7 +187,7 @@ Total {{ number_format($mutation->mutationDetails->sum('quantity_requested'), 2) }} - @if($mutation->status->value === 'received' || $mutation->status->value === 'approved' || $mutation->status->value === 'completed') + @if($mutation->status->value === 'received' || $mutation->status->value === 'approved') {{ number_format($mutation->mutationDetails->sum('quantity_approved'), 2) }} @else - @@ -225,10 +225,8 @@ @endif @if($mutation->status->value === 'approved') - - + + Stock Telah Dipindahkan @endif @if($mutation->canBeCancelled() && (auth()->user()->dealer_id == $mutation->from_dealer_id || auth()->user()->hasRole('admin'))) @@ -308,7 +306,7 @@ -

Setelah menerima, mutasi akan menunggu persetujuan dari pengirim sebelum stock dipindahkan.

+

Setelah menerima, mutasi akan menunggu persetujuan dari pengirim. Stock akan dipindahkan otomatis setelah disetujui.

-

Setelah disetujui, stock akan siap untuk dipindahkan.

+

Setelah disetujui, stock akan dipindahkan secara otomatis.

@endif -@if($mutation->status->value === 'approved') - - -@endif - @if($mutation->canBeCancelled() && (auth()->user()->dealer_id == $mutation->from_dealer_id || auth()->user()->hasRole('admin')))