diff --git a/app/Http/Controllers/WarehouseManagement/MutationsController.php b/app/Http/Controllers/WarehouseManagement/MutationsController.php index e75eb34..f5570ba 100644 --- a/app/Http/Controllers/WarehouseManagement/MutationsController.php +++ b/app/Http/Controllers/WarehouseManagement/MutationsController.php @@ -19,7 +19,7 @@ class MutationsController extends Controller $menu = Menu::where('link','mutations.index')->first(); if ($request->ajax()) { - $data = Mutation::with(['fromDealer', 'toDealer', 'requestedBy', 'approvedBy', 'receivedBy']) + $data = Mutation::with(['fromDealer', 'toDealer', 'requestedBy.role', 'approvedBy.role', 'receivedBy.role']) ->select('mutations.*'); // Filter berdasarkan dealer jika user bukan admin @@ -47,7 +47,19 @@ class MutationsController extends Controller ->addColumn('status', function($row) { $statusColor = $row->status_color; $statusLabel = $row->status_label; - return " {$statusLabel}"; + + $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 "{$statusLabel}"; }) ->addColumn('total_items', function($row) { return number_format($row->total_items, 0); @@ -79,7 +91,6 @@ class MutationsController extends Controller $request->validate([ 'from_dealer_id' => 'required|exists:dealers,id', 'to_dealer_id' => 'required|exists:dealers,id|different:from_dealer_id', - 'notes' => 'nullable|string', 'products' => 'required|array|min:1', 'products.*.product_id' => 'required|exists:products,id', 'products.*.quantity_requested' => 'required|numeric|min:0.01' @@ -92,8 +103,7 @@ class MutationsController extends Controller 'from_dealer_id' => $request->from_dealer_id, 'to_dealer_id' => $request->to_dealer_id, 'status' => 'sent', - 'requested_by' => auth()->id(), - 'notes' => $request->notes + 'requested_by' => auth()->id() ]); // Buat mutation details @@ -101,8 +111,7 @@ class MutationsController extends Controller MutationDetail::create([ 'mutation_id' => $mutation->id, 'product_id' => $productData['product_id'], - 'quantity_requested' => $productData['quantity_requested'], - 'notes' => $productData['notes'] ?? null + 'quantity_requested' => $productData['quantity_requested'] ]); } @@ -118,24 +127,63 @@ class MutationsController extends Controller public function show(Mutation $mutation) { - $mutation->load(['fromDealer', 'toDealer', 'requestedBy', 'approvedBy', 'receivedBy', 'mutationDetails.product']); + $mutation->load(['fromDealer', 'toDealer', 'requestedBy.role', 'approvedBy.role', 'receivedBy.role', 'mutationDetails.product']); return view('warehouse_management.mutations.show', compact('mutation')); } - public function receive(Mutation $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()]); } } @@ -143,34 +191,21 @@ class MutationsController extends Controller public function approve(Request $request, Mutation $mutation) { $request->validate([ - 'notes' => 'nullable|string', - 'details' => 'required|array', - 'details.*.quantity_approved' => 'required|numeric|min:0' + 'notes' => 'nullable|string' ]); if (!$mutation->canBeApproved()) { return back()->withErrors(['error' => 'Mutasi tidak dapat disetujui dalam status saat ini']); } - DB::beginTransaction(); try { - // Update mutation details dengan quantity approved - foreach ($request->details as $detailId => $detailData) { - $mutationDetail = MutationDetail::findOrFail($detailId); - $mutationDetail->update([ - 'quantity_approved' => $detailData['quantity_approved'] - ]); - } - - // Approve mutation + // Approve mutation (quantity_approved sudah diisi saat receive) $mutation->approve(auth()->id(), $request->notes); - DB::commit(); return redirect()->route('mutations.index') ->with('success', 'Mutasi berhasil disetujui'); } catch (\Exception $e) { - DB::rollback(); return back()->withErrors(['error' => 'Gagal menyetujui mutasi: ' . $e->getMessage()]); } } @@ -230,36 +265,7 @@ class MutationsController extends Controller } } - // API untuk mendapatkan detail mutasi untuk approval - public function getDetails(Mutation $mutation) - { - $mutation->load(['mutationDetails.product', 'fromDealer']); - - $details = $mutation->mutationDetails->map(function($detail) use ($mutation) { - $availableStock = $detail->product->getStockByDealer($mutation->from_dealer_id); - - return [ - 'id' => $detail->id, - 'product' => [ - 'id' => $detail->product->id, - 'name' => $detail->product->name - ], - 'quantity_requested' => $detail->quantity_requested, - 'quantity_approved' => $detail->quantity_approved, - 'available_stock' => $availableStock - ]; - }); - return response()->json([ - 'mutation' => [ - 'id' => $mutation->id, - 'mutation_number' => $mutation->mutation_number, - 'from_dealer' => $mutation->fromDealer->name, - 'to_dealer' => $mutation->toDealer->name - ], - 'details' => $details - ]); - } // API untuk mendapatkan stock produk di dealer tertentu public function getProductStock(Request $request) diff --git a/app/Http/Controllers/WarehouseManagement/OpnamesController.php b/app/Http/Controllers/WarehouseManagement/OpnamesController.php index b86d041..5177d1e 100644 --- a/app/Http/Controllers/WarehouseManagement/OpnamesController.php +++ b/app/Http/Controllers/WarehouseManagement/OpnamesController.php @@ -39,14 +39,25 @@ class OpnamesController extends Controller return Carbon::parse($row->created_at)->format('d M Y H:i'); }) ->editColumn('status', function ($row) { - $statusClass = [ + $statusColor = [ 'draft' => 'warning', 'pending' => 'info', 'approved' => 'success', 'rejected' => 'danger' ][$row->status] ?? 'secondary'; - return '' . ucfirst($row->status) . ''; + $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 "" . ucfirst($row->status) . ""; }) ->addColumn('action', function ($row) use ($menu) { $btn = '
`s get reset. However, we also reset the\n// bottom margin to use `rem` units instead of `em`.\n\np {\n margin-top: 0;\n margin-bottom: $paragraph-margin-bottom;\n}\n\n\n// Abbreviations\n//\n// 1. Duplicate behavior to the data-bs-* attribute for our tooltip plugin\n// 2. Add the correct text decoration in Chrome, Edge, Opera, and Safari.\n// 3. Add explicit cursor to indicate changed behavior.\n// 4. Prevent the text-decoration to be skipped.\n\nabbr[title],\nabbr[data-bs-original-title] { // 1\n text-decoration: underline dotted; // 2\n cursor: help; // 3\n text-decoration-skip-ink: none; // 4\n}\n\n\n// Address\n\naddress {\n margin-bottom: 1rem;\n font-style: normal;\n line-height: inherit;\n}\n\n\n// Lists\n\nol,\nul {\n padding-left: 2rem;\n}\n\nol,\nul,\ndl {\n margin-top: 0;\n margin-bottom: 1rem;\n}\n\nol ol,\nul ul,\nol ul,\nul ol {\n margin-bottom: 0;\n}\n\ndt {\n font-weight: $dt-font-weight;\n}\n\n// 1. Undo browser default\n\ndd {\n margin-bottom: .5rem;\n margin-left: 0; // 1\n}\n\n\n// Blockquote\n\nblockquote {\n margin: 0 0 1rem;\n}\n\n\n// Strong\n//\n// Add the correct font weight in Chrome, Edge, and Safari\n\nb,\nstrong {\n font-weight: $font-weight-bolder;\n}\n\n\n// Small\n//\n// Add the correct font size in all browsers\n\nsmall {\n @include font-size($small-font-size);\n}\n\n\n// Mark\n\nmark {\n padding: $mark-padding;\n background-color: $mark-bg;\n}\n\n\n// Sub and Sup\n//\n// Prevent `sub` and `sup` elements from affecting the line height in\n// all browsers.\n\nsub,\nsup {\n position: relative;\n @include font-size($sub-sup-font-size);\n line-height: 0;\n vertical-align: baseline;\n}\n\nsub { bottom: -.25em; }\nsup { top: -.5em; }\n\n\n// Links\n\na {\n color: $link-color;\n text-decoration: $link-decoration;\n\n &:hover {\n color: $link-hover-color;\n text-decoration: $link-hover-decoration;\n }\n}\n\n// And undo these styles for placeholder links/named anchors (without href).\n// It would be more straightforward to just use a[href] in previous block, but that\n// causes specificity issues in many other styles that are too complex to fix.\n// See https://github.com/twbs/bootstrap/issues/19402\n\na:not([href]):not([class]) {\n &,\n &:hover {\n color: inherit;\n text-decoration: none;\n }\n}\n\n\n// Code\n\npre,\ncode,\nkbd,\nsamp {\n font-family: $font-family-code;\n @include font-size(1em); // Correct the odd `em` font sizing in all browsers.\n direction: ltr #{\"/* rtl:ignore */\"};\n unicode-bidi: bidi-override;\n}\n\n// 1. Remove browser default top margin\n// 2. Reset browser default of `1em` to use `rem`s\n// 3. Don't allow content to break outside\n\npre {\n display: block;\n margin-top: 0; // 1\n margin-bottom: 1rem; // 2\n overflow: auto; // 3\n @include font-size($code-font-size);\n color: $pre-color;\n\n // Account for some code outputs that place code tags in pre tags\n code {\n @include font-size(inherit);\n color: inherit;\n word-break: normal;\n }\n}\n\ncode {\n @include font-size($code-font-size);\n color: $code-color;\n word-wrap: break-word;\n\n // Streamline the style when inside anchors to avoid broken underline and more\n a > & {\n color: inherit;\n }\n}\n\nkbd {\n padding: $kbd-padding-y $kbd-padding-x;\n @include font-size($kbd-font-size);\n color: $kbd-color;\n background-color: $kbd-bg;\n @include border-radius($border-radius-sm);\n\n kbd {\n padding: 0;\n @include font-size(1em);\n font-weight: $nested-kbd-font-weight;\n }\n}\n\n\n// Figures\n//\n// Apply a consistent margin strategy (matches our type styles).\n\nfigure {\n margin: 0 0 1rem;\n}\n\n\n// Images and content\n\nimg,\nsvg {\n vertical-align: middle;\n}\n\n\n// Tables\n//\n// Prevent double borders\n\ntable {\n caption-side: bottom;\n border-collapse: collapse;\n}\n\ncaption {\n padding-top: $table-cell-padding-y;\n padding-bottom: $table-cell-padding-y;\n color: $table-caption-color;\n text-align: left;\n}\n\n// 1. Removes font-weight bold by inheriting\n// 2. Matches default `