remove status pending and complete

This commit is contained in:
2025-06-15 02:29:26 +07:00
parent 3fb598ae4d
commit 9cfb566aee
13 changed files with 666 additions and 236 deletions

View File

@@ -0,0 +1,97 @@
<?php
namespace App\Console\Commands;
use Illuminate\Console\Command;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Schema;
class CleanMutationsData extends Command
{
/**
* The name and signature of the console command.
*
* @var string
*/
protected $signature = 'mutations:clean {--force : Force cleanup without confirmation}';
/**
* The console command description.
*
* @var string
*/
protected $description = 'Clean mutations data to allow migration rollback';
/**
* Create a new command instance.
*
* @return void
*/
public function __construct()
{
parent::__construct();
}
/**
* Execute the console command.
*/
public function handle()
{
if (!$this->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;
}
}
}

View File

@@ -4,23 +4,19 @@ namespace App\Enums;
enum MutationStatus: string enum MutationStatus: string
{ {
case PENDING = 'pending';
case SENT = 'sent'; case SENT = 'sent';
case RECEIVED = 'received'; case RECEIVED = 'received';
case APPROVED = 'approved'; case APPROVED = 'approved';
case REJECTED = 'rejected'; case REJECTED = 'rejected';
case COMPLETED = 'completed';
case CANCELLED = 'cancelled'; case CANCELLED = 'cancelled';
public function label(): string public function label(): string
{ {
return match($this) { return match($this) {
self::PENDING => 'Menunggu Konfirmasi',
self::SENT => 'Terkirim ke Dealer', self::SENT => 'Terkirim ke Dealer',
self::RECEIVED => 'Diterima Dealer', self::RECEIVED => 'Diterima Dealer',
self::APPROVED => 'Disetujui', self::APPROVED => 'Disetujui & Stock Dipindahkan',
self::REJECTED => 'Ditolak', self::REJECTED => 'Ditolak',
self::COMPLETED => 'Selesai',
self::CANCELLED => 'Dibatalkan', self::CANCELLED => 'Dibatalkan',
}; };
} }
@@ -28,12 +24,10 @@ enum MutationStatus: string
public function color(): string public function color(): string
{ {
return match($this) { return match($this) {
self::PENDING => 'warning',
self::SENT => 'primary', self::SENT => 'primary',
self::RECEIVED => 'info', self::RECEIVED => 'info',
self::APPROVED => 'brand', self::APPROVED => 'brand',
self::REJECTED => 'danger', self::REJECTED => 'danger',
self::COMPLETED => 'success',
self::CANCELLED => 'secondary', self::CANCELLED => 'secondary',
}; };
} }
@@ -55,12 +49,10 @@ enum MutationStatus: string
public static function getOptions(): array public static function getOptions(): array
{ {
return [ return [
self::PENDING->value => self::PENDING->label(),
self::SENT->value => self::SENT->label(), self::SENT->value => self::SENT->label(),
self::RECEIVED->value => self::RECEIVED->label(), self::RECEIVED->value => self::RECEIVED->label(),
self::APPROVED->value => self::APPROVED->label(), self::APPROVED->value => self::APPROVED->label(),
self::REJECTED->value => self::REJECTED->label(), self::REJECTED->value => self::REJECTED->label(),
self::COMPLETED->value => self::COMPLETED->label(),
self::CANCELLED->value => self::CANCELLED->label(), self::CANCELLED->value => self::CANCELLED->label(),
]; ];
} }

View File

@@ -182,8 +182,18 @@ class MutationsController extends Controller
$mutation->receive(auth()->id(), $request->reception_notes); $mutation->receive(auth()->id(), $request->reception_notes);
DB::commit(); 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) { } catch (\Exception $e) {
DB::rollback(); DB::rollback();
@@ -202,11 +212,25 @@ class MutationsController extends Controller
} }
try { try {
// Approve mutation (quantity_approved sudah diisi saat receive) // Approve mutation (stock will move automatically)
$mutation->approve(auth()->id(), $request->approval_notes); $mutation->approve(auth()->id(), $request->approval_notes);
return redirect()->route('mutations.index') // Check user role and redirect accordingly
->with('success', 'Mutasi berhasil disetujui'); 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) { } catch (\Exception $e) {
return back()->withErrors(['error' => 'Gagal menyetujui mutasi: ' . $e->getMessage()]); return back()->withErrors(['error' => 'Gagal menyetujui mutasi: ' . $e->getMessage()]);
@@ -226,30 +250,29 @@ class MutationsController extends Controller
try { try {
$mutation->reject(auth()->id(), $request->rejection_reason); $mutation->reject(auth()->id(), $request->rejection_reason);
return redirect()->route('mutations.index') // Check user role and redirect accordingly
->with('success', 'Mutasi berhasil ditolak'); 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) { } catch (\Exception $e) {
return back()->withErrors(['error' => 'Gagal menolak mutasi: ' . $e->getMessage()]); return back()->withErrors(['error' => 'Gagal menolak mutasi: ' . $e->getMessage()]);
} }
} }
public function complete(Mutation $mutation) // Complete method removed - Stock moves automatically after approval
{
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()]);
}
}
public function cancel(Request $request, Mutation $mutation) public function cancel(Request $request, Mutation $mutation)
{ {
@@ -294,9 +317,20 @@ class MutationsController extends Controller
{ {
$dealerId = $request->dealer_id; $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']) $data = Mutation::with(['fromDealer', 'toDealer', 'requestedBy.role'])
->where('to_dealer_id', $dealerId) ->where(function($query) use ($dealerId) {
->where('status', 'sent') // 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.*'); ->select('mutations.*');
return DataTables::of($data) return DataTables::of($data)
@@ -307,6 +341,9 @@ class MutationsController extends Controller
->addColumn('from_dealer', function($row) { ->addColumn('from_dealer', function($row) {
return $row->fromDealer->name ?? '-'; return $row->fromDealer->name ?? '-';
}) })
->addColumn('to_dealer', function($row) {
return $row->toDealer->name ?? '-';
})
->addColumn('status', function($row) { ->addColumn('status', function($row) {
$statusColor = $row->status_color; $statusColor = $row->status_color;
$statusLabel = $row->status_label; $statusLabel = $row->status_label;
@@ -330,10 +367,28 @@ class MutationsController extends Controller
->addColumn('created_at', function($row) { ->addColumn('created_at', function($row) {
return $row->created_at->format('d/m/Y H:i'); return $row->created_at->format('d/m/Y H:i');
}) })
->addColumn('action', function($row) { ->addColumn('action', function($row) use ($dealerId) {
return '<button type="button" class="btn btn-info btn-sm btn-detail" onclick="showMutationDetail('.$row->id.')"> $buttons = '';
Detail
</button>'; if ($row->status->value === 'sent' && $row->to_dealer_id == $dealerId) {
// For sent mutations where current dealer is recipient - show detail button for receiving
$buttons .= '<button type="button" class="btn btn-info btn-sm btn-detail" onclick="showMutationDetail('.$row->id.')">
Detail & Terima
</button>';
} elseif ($row->status->value === 'received' && $row->to_dealer_id == $dealerId) {
// For received mutations where current dealer is recipient - show approve/reject buttons
$buttons .= '<button type="button" class="btn btn-info btn-sm btn-detail mr-1" onclick="showMutationDetail('.$row->id.')">
Detail
</button>';
$buttons .= '<button type="button" class="btn btn-success btn-sm btn-approve-mutation mr-1" data-id="'.$row->id.'">
Setujui
</button>';
$buttons .= '<button type="button" class="btn btn-danger btn-sm btn-reject-mutation" data-id="'.$row->id.'">
Tolak
</button>';
}
return $buttons;
}) })
->rawColumns(['status', 'action']) ->rawColumns(['status', 'action'])
->make(true); ->make(true);

View File

@@ -116,11 +116,6 @@ class Mutation extends Model
return $this->mutationDetails()->sum('quantity_approved'); return $this->mutationDetails()->sum('quantity_approved');
} }
public function canBeSent()
{
return $this->status === MutationStatus::PENDING;
}
public function canBeReceived() public function canBeReceived()
{ {
return $this->status === MutationStatus::SENT; return $this->status === MutationStatus::SENT;
@@ -131,28 +126,9 @@ class Mutation extends Model
return $this->status === MutationStatus::RECEIVED; return $this->status === MutationStatus::RECEIVED;
} }
public function canBeCompleted()
{
return $this->status === MutationStatus::APPROVED;
}
public function canBeCancelled() public function canBeCancelled()
{ {
return in_array($this->status, [MutationStatus::PENDING, MutationStatus::SENT]); return $this->status === 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;
} }
// Receive mutation by destination dealer // Receive mutation by destination dealer
@@ -172,19 +148,37 @@ class Mutation extends Model
return $this; return $this;
} }
// Approve mutation // Approve mutation and move stock immediately
public function approve($userId, $approvalNotes = null) public function approve($userId, $approvalNotes = null)
{ {
if (!$this->canBeApproved()) { if (!$this->canBeApproved()) {
throw new \Exception('Mutasi tidak dapat disetujui dalam status saat ini'); throw new \Exception('Mutasi tidak dapat disetujui dalam status saat ini');
} }
$this->update([ DB::beginTransaction();
'status' => MutationStatus::APPROVED, try {
'approved_by' => $userId, // Update status to approved first
'approved_at' => now(), $this->update([
'approval_notes' => $approvalNotes '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; return $this;
} }
@@ -223,32 +217,7 @@ class Mutation extends Model
return $this; return $this;
} }
// Complete mutation (actually move the stock) // Complete method removed - Stock moves automatically after approval
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;
}
private function processStockMovement(MutationDetail $detail) private function processStockMovement(MutationDetail $detail)
{ {

View File

@@ -52,7 +52,7 @@ class MutationDetail extends Model
{ {
// Hanya dianggap ditolak jika mutasi sudah di-approve/reject dan quantity_approved = 0 // Hanya dianggap ditolak jika mutasi sudah di-approve/reject dan quantity_approved = 0
$mutationStatus = $this->mutation->status->value ?? null; $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() public function getApprovalStatusAttribute()
@@ -60,11 +60,11 @@ class MutationDetail extends Model
$mutationStatus = $this->mutation->status->value ?? null; $mutationStatus = $this->mutation->status->value ?? null;
// Jika mutasi belum di-approve, semua detail statusnya "Menunggu" // Jika mutasi belum di-approve, semua detail statusnya "Menunggu"
if (!in_array($mutationStatus, ['approved', 'completed', 'rejected'])) { if (!in_array($mutationStatus, ['approved', 'rejected'])) {
return 'Menunggu'; return 'Menunggu';
} }
// Jika mutasi sudah di-approve/complete, baru cek quantity_approved // Jika mutasi sudah di-approve, baru cek quantity_approved
if ($this->isFullyApproved()) { if ($this->isFullyApproved()) {
return 'Disetujui Penuh'; return 'Disetujui Penuh';
} elseif ($this->isPartiallyApproved()) { } elseif ($this->isPartiallyApproved()) {
@@ -81,11 +81,11 @@ class MutationDetail extends Model
$mutationStatus = $this->mutation->status->value ?? null; $mutationStatus = $this->mutation->status->value ?? null;
// Jika mutasi belum di-approve, semua detail statusnya "info" (menunggu) // 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'; return 'info';
} }
// Jika mutasi sudah di-approve/complete, baru cek quantity_approved // Jika mutasi sudah di-approve, baru cek quantity_approved
if ($this->isFullyApproved()) { if ($this->isFullyApproved()) {
return 'success'; return 'success';
} elseif ($this->isPartiallyApproved()) { } elseif ($this->isPartiallyApproved()) {

View File

@@ -16,7 +16,7 @@ return new class extends Migration
DB::table('mutation_details') DB::table('mutation_details')
->join('mutations', 'mutations.id', '=', 'mutation_details.mutation_id') ->join('mutations', 'mutations.id', '=', 'mutation_details.mutation_id')
->where('mutation_details.quantity_approved', 0) ->where('mutation_details.quantity_approved', 0)
->whereNotIn('mutations.status', ['approved', 'completed', 'rejected']) ->whereNotIn('mutations.status', ['approved', 'rejected'])
->update(['mutation_details.quantity_approved' => null]); ->update(['mutation_details.quantity_approved' => null]);
Schema::table('mutation_details', function (Blueprint $table) { Schema::table('mutation_details', function (Blueprint $table) {

View File

@@ -40,6 +40,9 @@ class AddAdditionalNotesAndRejectionFieldsToMutationsTable extends Migration
public function down() public function down()
{ {
Schema::table('mutations', function (Blueprint $table) { Schema::table('mutations', function (Blueprint $table) {
$table->dropForeign(['rejected_by']);
$table->dropForeign(['cancelled_by']);
// Remove new fields // Remove new fields
$table->dropColumn([ $table->dropColumn([
'reception_notes', 'reception_notes',

View File

@@ -0,0 +1,36 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
use Illuminate\Support\Facades\DB;
return new class extends Migration
{
/**
* Run the migrations.
*/
public function up(): void
{
// First, update any existing records that might have 'pending' or 'completed' status
DB::table('mutations')
->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'");
}
};

View File

@@ -0,0 +1,50 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
use Illuminate\Support\Facades\DB;
return new class extends Migration
{
/**
* Run the migrations.
*/
public function up(): void
{
// Clean up existing data and update status enum without touching old migrations
// First backup existing data (optional)
// DB::statement("CREATE TABLE mutations_backup AS SELECT * FROM mutations");
// Update existing 'pending' status to 'sent'
DB::table('mutations')
->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'");
}
};

View File

@@ -99,18 +99,18 @@ class MutationTestSeeder extends Seeder
'notes' => 'Produk approved parsial' 'notes' => 'Produk approved parsial'
]); ]);
// 4. Mutation dengan status COMPLETED (selesai) // 4. Additional APPROVED mutation (completed workflow is now just approved)
$this->command->info('Creating COMPLETED mutation...'); $this->command->info('Creating additional APPROVED mutation...');
$mutation4 = Mutation::create([ $mutation4 = Mutation::create([
'from_dealer_id' => $dealers[0]->id, 'from_dealer_id' => $dealers[0]->id,
'to_dealer_id' => $dealers[1]->id, 'to_dealer_id' => $dealers[1]->id,
'status' => MutationStatus::COMPLETED, 'status' => MutationStatus::APPROVED,
'requested_by' => $users[0]->id, 'requested_by' => $users[0]->id,
'received_by' => $users[1]->id ?? $users[0]->id, 'received_by' => $users[1]->id ?? $users[0]->id,
'received_at' => now()->subDay(), 'received_at' => now()->subDay(),
'approved_by' => $users[0]->id, 'approved_by' => $users[0]->id,
'approved_at' => now()->subHours(6), 'approved_at' => now()->subHours(6),
'notes' => 'Mutasi test - status COMPLETED' 'notes' => 'Mutasi test - status APPROVED (stock moved)'
]); ]);
MutationDetail::create([ MutationDetail::create([
@@ -118,7 +118,7 @@ class MutationTestSeeder extends Seeder
'product_id' => $products[1]->id, 'product_id' => $products[1]->id,
'quantity_requested' => 6.00, 'quantity_requested' => 6.00,
'quantity_approved' => 6.00, 'quantity_approved' => 6.00,
'notes' => 'Produk completed' 'notes' => 'Produk approved & stock moved'
]); ]);
// 5. Mutation dengan status REJECTED // 5. Mutation dengan status REJECTED
@@ -147,8 +147,8 @@ class MutationTestSeeder extends Seeder
$this->command->info('Test mutations created successfully!'); $this->command->info('Test mutations created successfully!');
$this->command->info('- Mutation SENT: ' . $mutation1->mutation_number); $this->command->info('- Mutation SENT: ' . $mutation1->mutation_number);
$this->command->info('- Mutation RECEIVED: ' . $mutation2->mutation_number); $this->command->info('- Mutation RECEIVED: ' . $mutation2->mutation_number);
$this->command->info('- Mutation APPROVED: ' . $mutation3->mutation_number); $this->command->info('- Mutation APPROVED (1): ' . $mutation3->mutation_number);
$this->command->info('- Mutation COMPLETED: ' . $mutation4->mutation_number); $this->command->info('- Mutation APPROVED (2): ' . $mutation4->mutation_number);
$this->command->info('- Mutation REJECTED: ' . $mutation5->mutation_number); $this->command->info('- Mutation REJECTED: ' . $mutation5->mutation_number);
} catch (\Exception $e) { } catch (\Exception $e) {

View File

@@ -164,6 +164,24 @@ use Illuminate\Support\Facades\Auth;
.mutation-detail-table input { .mutation-detail-table input {
font-size: 14px; 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;
}
</style> </style>
@endsection @endsection
@@ -718,16 +736,17 @@ use Illuminate\Support\Facades\Auth;
<!-- Tab Penerimaan Mutasi --> <!-- Tab Penerimaan Mutasi -->
<div class="tab-pane" id="penerimaan" role="tabpanel"> <div class="tab-pane" id="penerimaan" role="tabpanel">
<div class="mt-3"> <div class="mt-3">
<h6 class="mb-3">Daftar Mutasi yang Perlu Diterima</h6> <h6 class="mb-3">Daftar Mutasi yang Perlu Diterima & Disetujui</h6>
<div class="table-responsive"> <div class="table-responsive">
<table class="table table-bordered table-hover" id="receiveMutationsTable"> <table class="table table-bordered table-hover" id="receiveMutationsTable">
<thead class="thead-light"> <thead class="thead-light">
<tr> <tr>
<th width="20%">No. Mutasi</th> <th width="15%">No. Mutasi</th>
<th width="25%">Dealer Asal</th> <th width="20%">Dealer Asal</th>
<th width="15%">Status</th> <th width="20%">Dealer Tujuan</th>
<th width="10%">Total Item</th> <th width="12%">Status</th>
<th width="15%">Tanggal</th> <th width="8%">Total Item</th>
<th width="10%">Tanggal</th>
<th width="15%">Aksi</th> <th width="15%">Aksi</th>
</tr> </tr>
</thead> </thead>
@@ -764,6 +783,7 @@ use Illuminate\Support\Facades\Auth;
</div> </div>
<form id="receiveMutationForm" action="" method="POST"> <form id="receiveMutationForm" action="" method="POST">
@csrf @csrf
<input type="hidden" name="from_transaction_page" value="1">
<div class="modal-body"> <div class="modal-body">
<div id="mutationDetailContent"> <div id="mutationDetailContent">
<div class="text-center"> <div class="text-center">
@@ -775,7 +795,7 @@ use Illuminate\Support\Facades\Auth;
<div class="modal-footer"> <div class="modal-footer">
<button type="button" class="btn btn-secondary" data-dismiss="modal">Tutup</button> <button type="button" class="btn btn-secondary" data-dismiss="modal">Tutup</button>
<button type="submit" class="btn btn-success" id="receiveButton" style="display: none;"> <button type="submit" class="btn btn-success" id="receiveButton" style="display: none;">
<i class="fa fa-check"></i> Terima Mutasi <i class="fa fa-check"></i> Terima
</button> </button>
</div> </div>
</form> </form>
@@ -1312,6 +1332,16 @@ use Illuminate\Support\Facades\Auth;
setTimeout(function() { setTimeout(function() {
$('.nav-link[href="#mutasi"]').tab('show'); $('.nav-link[href="#mutasi"]').tab('show');
}, 100); }, 100);
@elseif(session('active_tab') == 'penerimaan')
// Activate stock tab and penerimaan sub-tab
$('.nav-link[href="#stock"]').tab('show');
setTimeout(function() {
$('.nav-link[href="#penerimaan"]').tab('show');
// Initialize table after tab is shown
setTimeout(function() {
initReceiveMutationsTable();
}, 200);
}, 100);
@endif @endif
@endif @endif
@@ -1348,8 +1378,8 @@ use Illuminate\Support\Facades\Auth;
var successMessage = '{{ session("success") }}'; var successMessage = '{{ session("success") }}';
var activeTab = '{{ session("active_tab") }}'; var activeTab = '{{ session("active_tab") }}';
if (successMessage.toLowerCase().includes('mutasi') || activeTab === 'mutasi') { if (successMessage.toLowerCase().includes('mutasi') && (successMessage.toLowerCase().includes('berhasil dibuat') || activeTab === 'mutasi')) {
// Reset mutasi form after success // Reset mutasi form after success for CREATING mutations
$('#mutasiForm')[0].reset(); $('#mutasiForm')[0].reset();
$('#products-tbody-mutasi').html(` $('#products-tbody-mutasi').html(`
<tr class="product-row-mutasi" data-index="0"> <tr class="product-row-mutasi" data-index="0">
@@ -1385,6 +1415,38 @@ use Illuminate\Support\Facades\Auth;
$("#btn-save-mutasi").attr("disabled", false); $("#btn-save-mutasi").attr("disabled", false);
$("#btn-save-mutasi").removeClass("disabled"); $("#btn-save-mutasi").removeClass("disabled");
$("#btn-save-mutasi").html('Kirim Mutasi'); $("#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') { } else if (successMessage.toLowerCase().includes('opname') || activeTab === 'opname') {
// Reset opname form after success // Reset opname form after success
$('#opnameForm')[0].reset(); $('#opnameForm')[0].reset();
@@ -1645,6 +1707,7 @@ use Illuminate\Support\Facades\Auth;
columns: [ columns: [
{data: 'mutation_number', name: 'mutation_number'}, {data: 'mutation_number', name: 'mutation_number'},
{data: 'from_dealer', name: 'from_dealer'}, {data: 'from_dealer', name: 'from_dealer'},
{data: 'to_dealer', name: 'to_dealer'},
{data: 'status', name: 'status', orderable: false}, {data: 'status', name: 'status', orderable: false},
{data: 'total_items', name: 'total_items'}, {data: 'total_items', name: 'total_items'},
{data: 'created_at', name: 'created_at'}, {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 // Show mutation detail modal
function showMutationDetail(mutationId) { function showMutationDetail(mutationId) {
$('#mutationDetailModal').modal('show'); $('#mutationDetailModal').modal('show');
@@ -1698,6 +1763,8 @@ use Illuminate\Support\Facades\Auth;
function renderMutationDetail(mutation) { function renderMutationDetail(mutation) {
var statusColor = mutation.status_color; var statusColor = mutation.status_color;
var statusLabel = mutation.status_label; var statusLabel = mutation.status_label;
var isReceived = mutation.status.value === 'received';
var canBeReceived = mutation.can_be_received;
// Set form action URL // Set form action URL
$('#receiveMutationForm').attr('action', '{{ route("mutations.receive", ":id") }}'.replace(':id', mutation.id)); $('#receiveMutationForm').attr('action', '{{ route("mutations.receive", ":id") }}'.replace(':id', mutation.id));
@@ -1735,13 +1802,6 @@ use Illuminate\Support\Facades\Auth;
<hr> <hr>
<div class="row mb-3">
<div class="col-md-12">
<label for="mutationNotes"><strong>Catatan Penerimaan:</strong></label>
<textarea name="reception_notes" id="mutationNotes" class="form-control" rows="3" placeholder="Masukkan catatan jika diperlukan..."></textarea>
</div>
</div>
<h6 class="mb-3">Detail Produk & Penerimaan:</h6> <h6 class="mb-3">Detail Produk & Penerimaan:</h6>
<div class="table-responsive"> <div class="table-responsive">
<table class="table table-bordered mutation-detail-table"> <table class="table table-bordered mutation-detail-table">
@@ -1756,9 +1816,12 @@ use Illuminate\Support\Facades\Auth;
<tbody> <tbody>
`; `;
// 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) { if (mutation.mutation_details && mutation.mutation_details.length > 0) {
mutation.mutation_details.forEach(function(detail) { mutation.mutation_details.forEach(function(detail) {
var quantityValue = detail.quantity_approved || detail.quantity_requested;
var notesValue = detail.notes || '';
detailHtml += ` detailHtml += `
<tr> <tr>
<td>${detail.product.name}</td> <td>${detail.product.name}</td>
@@ -1766,21 +1829,53 @@ use Illuminate\Support\Facades\Auth;
<span class="font-weight-bold text-info">${parseFloat(detail.quantity_requested).toFixed(2)}</span> <span class="font-weight-bold text-info">${parseFloat(detail.quantity_requested).toFixed(2)}</span>
</td> </td>
<td> <td>
<input type="number" `;
name="products[${detail.id}][quantity_approved]"
class="form-control quantity-approved-input" if (canBeReceived && !isReceived) {
min="0" // Editable input for mutations that can be received
max="${detail.quantity_requested}" detailHtml += `
step="0.01" <input type="number"
value="${detail.quantity_requested}" name="products[${detail.id}][quantity_approved]"
data-max="${detail.quantity_requested}" class="form-control quantity-approved-input"
placeholder="0.00"> min="0"
max="${detail.quantity_requested}"
step="0.01"
value="${detail.quantity_requested}"
data-max="${detail.quantity_requested}"
placeholder="0.00">
`;
} else {
// Read-only display for received mutations
detailHtml += `
<span class="font-weight-bold ${quantityValue == detail.quantity_requested ? 'text-success' : 'text-warning'}">
${parseFloat(quantityValue).toFixed(2)}
</span>
${quantityValue != detail.quantity_requested ?
'<small class="text-muted d-block">(Sebagian)</small>' : ''}
`;
}
detailHtml += `
</td> </td>
<td> <td>
<textarea name="products[${detail.id}][notes]" `;
class="form-control"
rows="2" if (canBeReceived && !isReceived) {
placeholder="Catatan untuk produk ini..."></textarea> // Editable textarea for mutations that can be received
detailHtml += `
<textarea name="products[${detail.id}][notes]"
class="form-control"
rows="2"
placeholder="Catatan untuk produk ini...">${notesValue}</textarea>
`;
} else {
// Read-only display for received mutations
detailHtml += `
<span class="text-muted">${notesValue || '-'}</span>
`;
}
detailHtml += `
</td> </td>
</tr> </tr>
`; `;
@@ -1798,21 +1893,76 @@ use Illuminate\Support\Facades\Auth;
</table> </table>
</div> </div>
<div class="alert alert-info"> <div class="row mb-3">
<i class="fa fa-info-circle"></i> <div class="col-md-12">
<strong>Petunjuk:</strong> <label for="mutationNotes"><strong>Catatan Penerimaan:</strong></label>
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 += `
<textarea name="reception_notes" id="mutationNotes" class="form-control" rows="3"
placeholder="Masukkan catatan kondisi barang saat diterima (opsional)...">${mutation.reception_notes || ''}</textarea>
`;
} else {
// Read-only display for received mutations
detailHtml += `
<div class="form-control-plaintext border rounded p-2 bg-light" style="min-height: 60px;">
${mutation.reception_notes || '<em class="text-muted">Tidak ada catatan</em>'}
</div>
`;
}
detailHtml += `
</div>
</div> </div>
`; `;
$('#mutationDetailContent').html(detailHtml); // Add instructions based on status
if (canBeReceived && !isReceived) {
// Show receive button if mutation can be received detailHtml += `
if (mutation.can_be_received) { <div class="alert alert-info mb-0">
$('#receiveButton').show(); <div class="d-flex align-items-start">
<i class="fa fa-info-circle mt-1 mr-2"></i>
<div>
<strong>Instruksi Penerimaan:</strong>
<ul class="mb-0 mt-2">
<li>Periksa kondisi fisik produk yang diterima</li>
<li>Masukkan quantity yang benar-benar diterima untuk setiap produk</li>
<li>Quantity yang disetujui tidak boleh melebihi quantity yang diminta</li>
<li>Berikan catatan jika ada produk yang rusak atau tidak sesuai</li>
</ul>
<div class="mt-2 p-2 rounded">
<small><strong>Perhatian:</strong> Setelah diterima, catatan tidak dapat diubah lagi. Pastikan informasi sudah benar sebelum menerima mutasi.</small>
</div>
</div>
</div>
</div>
`;
} else if (isReceived) {
detailHtml += `
<div class="alert alert-success mb-0">
<div class="d-flex align-items-center">
<i class="fa fa-check-circle mr-2"></i>
<div>
<strong>Status:</strong> Mutasi telah diterima dan siap untuk disetujui.
<br><small>Stock akan dipindahkan setelah Anda menyetujui mutasi ini.</small>
</div>
</div>
</div>
`;
} }
// 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() { $('.quantity-approved-input').on('input', function() {
var value = parseFloat($(this).val()) || 0; var value = parseFloat($(this).val()) || 0;
var max = parseFloat($(this).data('max')) || 0; var max = parseFloat($(this).data('max')) || 0;
@@ -1864,16 +2014,31 @@ use Illuminate\Support\Facades\Auth;
if (typeof Swal !== 'undefined') { if (typeof Swal !== 'undefined') {
Swal.fire({ Swal.fire({
title: 'Terima Mutasi?', title: 'Konfirmasi Penerimaan Mutasi',
text: "Mutasi akan diterima dengan quantity dan catatan yang telah Anda masukkan", html: `
type: 'question', <div class="text-left">
<p class="mb-3">Dengan menerima mutasi ini:</p>
<ul class="text-muted mb-3" style="font-size: 14px;">
<li>Anda mengkonfirmasi telah menerima produk dari dealer pengirim</li>
<li>Data quantity dan catatan yang dimasukkan akan disimpan</li>
<li>Mutasi akan masuk ke tahap persetujuan untuk memindahkan stock</li>
<li>Catatan dan data penerimaan tidak dapat diubah setelah diterima</li>
</ul>
<div class="alert alert-info">
<i class="fa fa-info-circle mr-2"></i>
<small><strong>Info:</strong> Pastikan semua data sudah benar sebelum menerima mutasi.</small>
</div>
</div>
`,
icon: 'question',
showCancelButton: true, showCancelButton: true,
confirmButtonColor: '#28a745', confirmButtonColor: '#28a745',
cancelButtonColor: '#6c757d', cancelButtonColor: '#6c757d',
confirmButtonText: 'Ya, Terima', confirmButtonText: 'Ya, Terima Mutasi',
cancelButtonText: 'Batal' cancelButtonText: 'Batal',
width: '500px'
}).then((result) => { }).then((result) => {
if (result.value) { if (result.isConfirmed) {
// Set loading state // Set loading state
$('#receiveButton').prop('disabled', true).html('<i class="fa fa-spinner fa-spin"></i> Memproses...'); $('#receiveButton').prop('disabled', true).html('<i class="fa fa-spinner fa-spin"></i> Memproses...');
@@ -1896,6 +2061,138 @@ use Illuminate\Support\Facades\Auth;
}, 100); }, 100);
}); });
// Handle approve button click
$(document).on('click', '.btn-approve-mutation', function() {
var mutationId = $(this).data('id');
Swal.fire({
title: 'Konfirmasi Persetujuan Mutasi',
html: `
<div class="text-left">
<p class="mb-3">Dengan menyetujui mutasi ini:</p>
<ul class="text-muted mb-3" style="font-size: 14px;">
<li>Stock akan dipindahkan secara otomatis dari dealer asal ke dealer tujuan</li>
<li>Proses mutasi akan selesai dan tidak dapat dibatalkan</li>
<li>Perubahan stock akan tercatat dalam log sistem</li>
</ul>
<div class="form-group text-left">
<label for="approval-notes" class="font-weight-bold">Catatan Persetujuan:</label>
<textarea id="approval-notes" class="form-control" rows="3" placeholder="Masukkan catatan persetujuan (opsional)..."></textarea>
</div>
</div>
`,
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 = $('<form>').attr({
method: 'POST',
action: '{{ route("mutations.approve", ":id") }}'.replace(':id', mutationId)
});
form.append($('<input>').attr({
type: 'hidden',
name: '_token',
value: $('meta[name="csrf-token"]').attr('content')
}));
form.append($('<input>').attr({
type: 'hidden',
name: 'from_transaction_page',
value: '1'
}));
if (result.value) {
form.append($('<input>').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: `
<div class="text-left">
<div class="alert alert-warning mb-3">
<i class="fa fa-exclamation-triangle mr-2"></i>
<strong>Perhatian:</strong> Mutasi yang ditolak tidak dapat diubah lagi dan proses akan dihentikan.
</div>
<div class="form-group text-left">
<label for="rejection-reason" class="font-weight-bold">Alasan Penolakan: <span class="text-danger">*</span></label>
<textarea id="rejection-reason" class="form-control" rows="3" placeholder="Jelaskan alasan penolakan mutasi ini..." required></textarea>
<small class="text-muted">Alasan penolakan wajib diisi untuk dokumentasi.</small>
</div>
</div>
`,
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 = $('<form>').attr({
method: 'POST',
action: '{{ route("mutations.reject", ":id") }}'.replace(':id', mutationId)
});
form.append($('<input>').attr({
type: 'hidden',
name: '_token',
value: $('meta[name="csrf-token"]').attr('content')
}));
form.append($('<input>').attr({
type: 'hidden',
name: 'from_transaction_page',
value: '1'
}));
form.append($('<input>').attr({
type: 'hidden',
name: 'rejection_reason',
value: result.value
}));
$('body').append(form);
form.submit();
}
});
});
// Save active tab to localStorage // Save active tab to localStorage
$('.nav-link').on('click', function() { $('.nav-link').on('click', function() {
var target = $(this).attr('href'); var target = $(this).attr('href');

View File

@@ -52,25 +52,8 @@
@endif @endif
@if($row->status->value === 'approved') @if($row->status->value === 'approved')
<!-- Complete/Receive Button --> <!-- Stock has already been moved automatically after approval -->
@can('complete-mutation') <span class="badge badge-success">Stock Telah Dipindahkan</span>
<button type="button"
class="btn btn-sm btn-primary btn-complete mr-2"
data-id="{{ $row->id }}"
data-bs-toggle="modal"
data-bs-target="#completeModal{{ $row->id }}">
Selesaikan
</button>
@endcan
<!-- Cancel Button -->
@can('edit-mutation')
<button type="button"
class="btn btn-sm btn-warning btn-cancel mr-2"
data-id="{{ $row->id }}">
Batal
</button>
@endcan
@endif @endif
</div> </div>
@@ -86,6 +69,7 @@
<div class="modal-body"> <div class="modal-body">
<div class="alert alert-info"> <div class="alert alert-info">
<strong>Konfirmasi!</strong> Anda akan menyetujui mutasi yang telah diterima oleh <strong>{{ $row->toDealer->name }}</strong>. <strong>Konfirmasi!</strong> Anda akan menyetujui mutasi yang telah diterima oleh <strong>{{ $row->toDealer->name }}</strong>.
<br><strong>Stock akan dipindahkan secara otomatis setelah disetujui.</strong>
</div> </div>
<div class="form-group"> <div class="form-group">
@@ -128,7 +112,7 @@
</table> </table>
</div> </div>
<p class="text-muted">Setelah disetujui, stock akan siap untuk dipindahkan.</p> <p class="text-muted">Setelah disetujui, stock akan dipindahkan secara otomatis.</p>
</div> </div>
<div class="modal-footer"> <div class="modal-footer">
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Batal</button> <button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Batal</button>
@@ -223,7 +207,7 @@
</table> </table>
</div> </div>
<p class="text-muted">Setelah menerima, mutasi akan menunggu persetujuan dari pengirim sebelum stock dipindahkan.</p> <p class="text-muted">Setelah menerima, mutasi akan menunggu persetujuan dari pengirim. Stock akan dipindahkan otomatis setelah disetujui.</p>
</div> </div>
<div class="modal-footer"> <div class="modal-footer">
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Batal</button> <button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Batal</button>
@@ -234,26 +218,4 @@
</div> </div>
</div> </div>
<!-- Modal untuk Complete --> <!-- Complete Modal is no longer needed since stock moves automatically after approval -->
<div class="modal fade" id="completeModal{{ $row->id }}" tabindex="-1" aria-labelledby="completeModalLabel{{ $row->id }}" aria-hidden="true">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title" id="completeModalLabel{{ $row->id }}">Selesaikan Mutasi</h5>
</div>
<form action="{{ route('mutations.complete', $row->id) }}" method="POST">
@csrf
<div class="modal-body">
<div class="alert alert-info">
<strong>Konfirmasi!</strong> Stock akan dipindahkan dari <strong>{{ $row->fromDealer->name }}</strong> ke <strong>{{ $row->toDealer->name }}</strong>.
</div>
<p>Apakah Anda yakin ingin menyelesaikan mutasi ini? Tindakan ini tidak dapat dibatalkan.</p>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Batal</button>
<button type="submit" class="btn btn-primary">Ya, Selesaikan</button>
</div>
</form>
</div>
</div>
</div>

View File

@@ -158,7 +158,7 @@
<td>{{ $detail->product->name }}</td> <td>{{ $detail->product->name }}</td>
<td class="text-center">{{ number_format($detail->quantity_requested, 2) }}</td> <td class="text-center">{{ number_format($detail->quantity_requested, 2) }}</td>
<td class="text-center"> <td class="text-center">
@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) }} {{ number_format($detail->quantity_approved ?? 0, 2) }}
@else @else
<span class="text-muted">Belum ditentukan</span> <span class="text-muted">Belum ditentukan</span>
@@ -187,7 +187,7 @@
<td colspan="2" class="text-right">Total</td> <td colspan="2" class="text-right">Total</td>
<td class="text-center">{{ number_format($mutation->mutationDetails->sum('quantity_requested'), 2) }}</td> <td class="text-center">{{ number_format($mutation->mutationDetails->sum('quantity_requested'), 2) }}</td>
<td class="text-center"> <td class="text-center">
@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) }} {{ number_format($mutation->mutationDetails->sum('quantity_approved'), 2) }}
@else @else
<span class="text-muted">-</span> <span class="text-muted">-</span>
@@ -225,10 +225,8 @@
@endif @endif
@if($mutation->status->value === 'approved') @if($mutation->status->value === 'approved')
<!-- Complete Button --> <!-- Stock has already been moved automatically after approval -->
<button type="button" class="btn btn-primary" data-toggle="modal" data-target="#completeModal"> <span class="badge badge-success">Stock Telah Dipindahkan</span>
Selesaikan Mutasi
</button>
@endif @endif
@if($mutation->canBeCancelled() && (auth()->user()->dealer_id == $mutation->from_dealer_id || auth()->user()->hasRole('admin'))) @if($mutation->canBeCancelled() && (auth()->user()->dealer_id == $mutation->from_dealer_id || auth()->user()->hasRole('admin')))
@@ -308,7 +306,7 @@
</table> </table>
</div> </div>
<p class="text-muted">Setelah menerima, mutasi akan menunggu persetujuan dari pengirim sebelum stock dipindahkan.</p> <p class="text-muted">Setelah menerima, mutasi akan menunggu persetujuan dari pengirim. Stock akan dipindahkan otomatis setelah disetujui.</p>
</div> </div>
<div class="modal-footer"> <div class="modal-footer">
<button type="button" class="btn btn-secondary" data-dismiss="modal">Batal</button> <button type="button" class="btn btn-secondary" data-dismiss="modal">Batal</button>
@@ -378,7 +376,7 @@
</table> </table>
</div> </div>
<p class="text-muted">Setelah disetujui, stock akan siap untuk dipindahkan.</p> <p class="text-muted">Setelah disetujui, stock akan dipindahkan secara otomatis.</p>
</div> </div>
<div class="modal-footer"> <div class="modal-footer">
<button type="button" class="btn btn-secondary" data-dismiss="modal">Batal</button> <button type="button" class="btn btn-secondary" data-dismiss="modal">Batal</button>
@@ -420,35 +418,6 @@
</div> </div>
@endif @endif
@if($mutation->status->value === 'approved')
<!-- Complete Modal -->
<div class="modal fade" id="completeModal" tabindex="-1" role="dialog">
<div class="modal-dialog" role="document">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title">Selesaikan Mutasi</h5>
<button type="button" class="close" data-dismiss="modal">
<span>&times;</span>
</button>
</div>
<form action="{{ route('mutations.complete', $mutation->id) }}" method="POST">
@csrf
<div class="modal-body">
<div class="alert alert-info">
<strong>Konfirmasi!</strong> Stock akan dipindahkan dari <strong>{{ $mutation->fromDealer->name }}</strong> ke <strong>{{ $mutation->toDealer->name }}</strong>.
</div>
<p>Apakah Anda yakin ingin menyelesaikan mutasi ini? Tindakan ini tidak dapat dibatalkan.</p>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary" data-dismiss="modal">Batal</button>
<button type="submit" class="btn btn-primary">Ya, Selesaikan</button>
</div>
</form>
</div>
</div>
</div>
@endif
@if($mutation->canBeCancelled() && (auth()->user()->dealer_id == $mutation->from_dealer_id || auth()->user()->hasRole('admin'))) @if($mutation->canBeCancelled() && (auth()->user()->dealer_id == $mutation->from_dealer_id || auth()->user()->hasRole('admin')))
<!-- Cancel Modal --> <!-- Cancel Modal -->
<div class="modal fade" id="cancelModal" tabindex="-1" role="dialog"> <div class="modal fade" id="cancelModal" tabindex="-1" role="dialog">