377 lines
14 KiB
PHP
377 lines
14 KiB
PHP
<?php
|
|
|
|
namespace App\Http\Controllers\WarehouseManagement;
|
|
use App\Http\Controllers\Controller;
|
|
use App\Models\Mutation;
|
|
use App\Models\MutationDetail;
|
|
use App\Models\Product;
|
|
use App\Models\Dealer;
|
|
use App\Enums\MutationStatus;
|
|
use App\Models\Menu;
|
|
use Illuminate\Http\Request;
|
|
use Illuminate\Support\Facades\DB;
|
|
use Yajra\DataTables\DataTables;
|
|
|
|
class MutationsController extends Controller
|
|
{
|
|
public function index(Request $request)
|
|
{
|
|
$menu = Menu::where('link','mutations.index')->first();
|
|
|
|
if ($request->ajax()) {
|
|
$data = Mutation::with(['fromDealer', 'toDealer', 'requestedBy.role', 'approvedBy.role', 'receivedBy.role'])
|
|
->select('mutations.*');
|
|
|
|
// Filter berdasarkan dealer jika user bukan admin
|
|
if (auth()->user()->dealer_id) {
|
|
$data->where(function($query) {
|
|
$query->where('from_dealer_id', auth()->user()->dealer_id)
|
|
->orWhere('to_dealer_id', auth()->user()->dealer_id);
|
|
});
|
|
}
|
|
|
|
return DataTables::of($data)
|
|
->addIndexColumn()
|
|
->addColumn('mutation_number', function($row) {
|
|
return $row->mutation_number;
|
|
})
|
|
->addColumn('from_dealer', function($row) {
|
|
return $row->fromDealer->name ?? '-';
|
|
})
|
|
->addColumn('to_dealer', function($row) {
|
|
return $row->toDealer->name ?? '-';
|
|
})
|
|
->addColumn('requested_by', function($row) {
|
|
return $row->requestedBy->name ?? '-';
|
|
})
|
|
->addColumn('status', function($row) {
|
|
$statusColor = $row->status_color;
|
|
$statusLabel = $row->status_label;
|
|
|
|
$textColorClass = match($statusColor) {
|
|
'success' => 'text-success',
|
|
'warning' => 'text-warning',
|
|
'danger' => 'text-danger',
|
|
'info' => 'text-info',
|
|
'primary' => 'text-primary',
|
|
'brand' => 'text-primary',
|
|
'secondary' => 'text-muted',
|
|
default => 'text-dark'
|
|
};
|
|
|
|
return "<span class=\"font-weight-bold {$textColorClass}\">{$statusLabel}</span>";
|
|
})
|
|
->addColumn('total_items', function($row) {
|
|
return number_format($row->total_items, 0);
|
|
})
|
|
->addColumn('created_at', function($row) {
|
|
return $row->created_at->format('d/m/Y H:i');
|
|
})
|
|
->addColumn('action', function($row) {
|
|
return view('warehouse_management.mutations._action', compact('row'))->render();
|
|
})
|
|
->rawColumns(['status', 'action'])
|
|
->make(true);
|
|
}
|
|
|
|
return view('warehouse_management.mutations.index', compact('menu'));
|
|
}
|
|
|
|
public function create()
|
|
{
|
|
$menu = Menu::where('link','mutations.create')->first();
|
|
$dealers = Dealer::all();
|
|
$products = Product::with('stocks')->get();
|
|
|
|
return view('warehouse_management.mutations.create', compact('menu', 'dealers', 'products'));
|
|
}
|
|
|
|
public function store(Request $request)
|
|
{
|
|
$request->validate([
|
|
'from_dealer_id' => 'required|exists:dealers,id',
|
|
'to_dealer_id' => 'required|exists:dealers,id|different:from_dealer_id',
|
|
'products' => 'required|array|min:1',
|
|
'products.*.product_id' => 'required|exists:products,id',
|
|
'products.*.quantity_requested' => 'required|numeric|min:0.01'
|
|
]);
|
|
|
|
DB::beginTransaction();
|
|
try {
|
|
// Buat mutation record dengan status SENT (langsung terkirim ke dealer tujuan)
|
|
$mutation = Mutation::create([
|
|
'from_dealer_id' => $request->from_dealer_id,
|
|
'to_dealer_id' => $request->to_dealer_id,
|
|
'status' => 'sent',
|
|
'requested_by' => auth()->id()
|
|
]);
|
|
|
|
// Buat mutation details
|
|
foreach ($request->products as $productData) {
|
|
MutationDetail::create([
|
|
'mutation_id' => $mutation->id,
|
|
'product_id' => $productData['product_id'],
|
|
'quantity_requested' => $productData['quantity_requested']
|
|
]);
|
|
}
|
|
|
|
DB::commit();
|
|
|
|
// Check if request came from transaction page
|
|
if ($request->has('from_transaction_page') || str_contains($request->header('referer', ''), '/transaction')) {
|
|
return redirect()->back()
|
|
->with('success', 'Mutasi berhasil dibuat dan terkirim ke dealer tujuan');
|
|
}
|
|
|
|
return redirect()->route('mutations.index')
|
|
->with('success', 'Mutasi berhasil dibuat dan terkirim ke dealer tujuan');
|
|
|
|
} catch (\Exception $e) {
|
|
DB::rollback();
|
|
return back()->withErrors(['error' => 'Gagal membuat mutasi: ' . $e->getMessage()]);
|
|
}
|
|
}
|
|
|
|
public function show(Mutation $mutation)
|
|
{
|
|
$mutation->load(['fromDealer', 'toDealer', 'requestedBy.role', 'approvedBy.role', 'receivedBy.role', 'mutationDetails.product']);
|
|
|
|
return view('warehouse_management.mutations.show', compact('mutation'));
|
|
}
|
|
|
|
public function receive(Request $request, Mutation $mutation)
|
|
{
|
|
$request->validate([
|
|
'notes' => 'nullable|string',
|
|
'products' => 'required|array',
|
|
'products.*.quantity_approved' => 'required|numeric|min:0',
|
|
'products.*.notes' => 'nullable|string'
|
|
]);
|
|
|
|
if (!$mutation->canBeReceived()) {
|
|
return back()->withErrors(['error' => 'Mutasi tidak dapat diterima dalam status saat ini']);
|
|
}
|
|
|
|
DB::beginTransaction();
|
|
try {
|
|
// Update mutation notes jika ada
|
|
if ($request->notes) {
|
|
$mutation->update(['notes' => $request->notes]);
|
|
}
|
|
|
|
// Update product details dengan quantity_approved dan notes
|
|
if ($request->products) {
|
|
foreach ($request->products as $detailId => $productData) {
|
|
$updateData = [];
|
|
|
|
// Set quantity_approved
|
|
if (isset($productData['quantity_approved'])) {
|
|
$updateData['quantity_approved'] = $productData['quantity_approved'];
|
|
}
|
|
|
|
// Set notes jika ada
|
|
if (isset($productData['notes']) && !empty($productData['notes'])) {
|
|
$updateData['notes'] = $productData['notes'];
|
|
}
|
|
|
|
if (!empty($updateData)) {
|
|
MutationDetail::where('id', $detailId)
|
|
->where('mutation_id', $mutation->id)
|
|
->update($updateData);
|
|
}
|
|
}
|
|
}
|
|
|
|
// Receive mutation
|
|
$mutation->receive(auth()->id());
|
|
|
|
DB::commit();
|
|
return redirect()->route('mutations.index')
|
|
->with('success', 'Mutasi berhasil diterima dan menunggu persetujuan pengirim');
|
|
|
|
} catch (\Exception $e) {
|
|
DB::rollback();
|
|
return back()->withErrors(['error' => 'Gagal menerima mutasi: ' . $e->getMessage()]);
|
|
}
|
|
}
|
|
|
|
public function approve(Request $request, Mutation $mutation)
|
|
{
|
|
$request->validate([
|
|
'notes' => 'nullable|string'
|
|
]);
|
|
|
|
if (!$mutation->canBeApproved()) {
|
|
return back()->withErrors(['error' => 'Mutasi tidak dapat disetujui dalam status saat ini']);
|
|
}
|
|
|
|
try {
|
|
// Approve mutation (quantity_approved sudah diisi saat receive)
|
|
$mutation->approve(auth()->id(), $request->notes);
|
|
|
|
return redirect()->route('mutations.index')
|
|
->with('success', 'Mutasi berhasil disetujui');
|
|
|
|
} catch (\Exception $e) {
|
|
return back()->withErrors(['error' => 'Gagal menyetujui mutasi: ' . $e->getMessage()]);
|
|
}
|
|
}
|
|
|
|
public function reject(Request $request, Mutation $mutation)
|
|
{
|
|
$request->validate([
|
|
'rejection_reason' => 'required|string'
|
|
]);
|
|
|
|
if (!$mutation->canBeApproved()) {
|
|
return back()->withErrors(['error' => 'Mutasi tidak dapat ditolak dalam status saat ini']);
|
|
}
|
|
|
|
try {
|
|
$mutation->reject(auth()->id(), $request->rejection_reason);
|
|
|
|
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()]);
|
|
}
|
|
}
|
|
|
|
public function cancel(Mutation $mutation)
|
|
{
|
|
if (!$mutation->canBeCancelled()) {
|
|
return back()->withErrors(['error' => 'Mutasi tidak dapat dibatalkan dalam status saat ini']);
|
|
}
|
|
|
|
try {
|
|
$mutation->update(['status' => MutationStatus::CANCELLED]);
|
|
|
|
return redirect()->route('mutations.index')
|
|
->with('success', 'Mutasi berhasil dibatalkan');
|
|
|
|
} catch (\Exception $e) {
|
|
return back()->withErrors(['error' => 'Gagal membatalkan mutasi: ' . $e->getMessage()]);
|
|
}
|
|
}
|
|
|
|
|
|
|
|
// API untuk mendapatkan stock produk di dealer tertentu
|
|
public function getProductStock(Request $request)
|
|
{
|
|
$dealerId = $request->dealer_id;
|
|
$productId = $request->product_id;
|
|
|
|
$product = Product::findOrFail($productId);
|
|
$stock = $product->getStockByDealer($dealerId);
|
|
|
|
return response()->json([
|
|
'product_name' => $product->name,
|
|
'current_stock' => $stock
|
|
]);
|
|
}
|
|
|
|
// API untuk mendapatkan mutasi yang perlu diterima oleh dealer
|
|
public function getPendingMutations(Request $request)
|
|
{
|
|
$dealerId = $request->dealer_id;
|
|
|
|
$data = Mutation::with(['fromDealer', 'toDealer', 'requestedBy.role'])
|
|
->where('to_dealer_id', $dealerId)
|
|
->where('status', 'sent')
|
|
->select('mutations.*');
|
|
|
|
return DataTables::of($data)
|
|
->addIndexColumn()
|
|
->addColumn('mutation_number', function($row) {
|
|
return $row->mutation_number;
|
|
})
|
|
->addColumn('from_dealer', function($row) {
|
|
return $row->fromDealer->name ?? '-';
|
|
})
|
|
->addColumn('status', function($row) {
|
|
$statusColor = $row->status_color;
|
|
$statusLabel = $row->status_label;
|
|
|
|
$textColorClass = match($statusColor) {
|
|
'success' => 'text-success',
|
|
'warning' => 'text-warning',
|
|
'danger' => 'text-danger',
|
|
'info' => 'text-info',
|
|
'primary' => 'text-primary',
|
|
'brand' => 'text-primary',
|
|
'secondary' => 'text-muted',
|
|
default => 'text-dark'
|
|
};
|
|
|
|
return "<span class=\"font-weight-bold {$textColorClass}\">{$statusLabel}</span>";
|
|
})
|
|
->addColumn('total_items', function($row) {
|
|
return number_format($row->total_items, 0);
|
|
})
|
|
->addColumn('created_at', function($row) {
|
|
return $row->created_at->format('d/m/Y H:i');
|
|
})
|
|
->addColumn('action', function($row) {
|
|
return '<button type="button" class="btn btn-info btn-sm btn-detail" onclick="showMutationDetail('.$row->id.')">
|
|
Detail
|
|
</button>';
|
|
})
|
|
->rawColumns(['status', 'action'])
|
|
->make(true);
|
|
}
|
|
|
|
// API untuk mendapatkan detail mutasi
|
|
public function getDetail(Mutation $mutation)
|
|
{
|
|
try {
|
|
$mutation->load([
|
|
'fromDealer',
|
|
'toDealer',
|
|
'requestedBy.role',
|
|
'approvedBy.role',
|
|
'receivedBy.role',
|
|
'mutationDetails.product'
|
|
]);
|
|
|
|
// Format created_at
|
|
$mutation->created_at_formatted = $mutation->created_at->format('d/m/Y H:i');
|
|
|
|
// Add status color and label
|
|
$mutation->status_color = $mutation->status_color;
|
|
$mutation->status_label = $mutation->status_label;
|
|
|
|
// Check if can be received
|
|
$mutation->can_be_received = $mutation->canBeReceived();
|
|
|
|
return response()->json([
|
|
'success' => true,
|
|
'data' => $mutation
|
|
]);
|
|
|
|
} catch (\Exception $e) {
|
|
return response()->json([
|
|
'success' => false,
|
|
'message' => 'Gagal memuat detail mutasi: ' . $e->getMessage()
|
|
], 500);
|
|
}
|
|
}
|
|
}
|