ajax()) { $data = WorkDealerPrice::with(['dealer']) ->where('work_id', $work->id) ->select('work_dealer_prices.*'); return DataTables::of($data) ->addIndexColumn() ->addColumn('dealer_name', function($row) { return $row->dealer->name; }) ->addColumn('formatted_price', function($row) { return $row->formatted_price; }) ->addColumn('action', function($row) { $btn = '
'; $btn .= ''; $btn .= ''; $btn .= '
'; return $btn; }) ->rawColumns(['action']) ->make(true); } $dealers = Dealer::all(); return view('back.master.work_prices', compact('work', 'dealers')); } /** * Store a newly created price */ public function store(Request $request) { try { $request->validate([ 'work_id' => 'required|exists:works,id', 'dealer_id' => 'required|exists:dealers,id', 'price' => 'required|numeric|min:0', 'currency' => 'required|string|max:3', 'is_active' => 'nullable|in:0,1', ], [ 'work_id.required' => 'ID pekerjaan harus diisi', 'work_id.exists' => 'Pekerjaan tidak ditemukan', 'dealer_id.required' => 'ID dealer harus diisi', 'dealer_id.exists' => 'Dealer tidak ditemukan', 'price.required' => 'Harga harus diisi', 'price.numeric' => 'Harga harus berupa angka', 'price.min' => 'Harga minimal 0', 'currency.required' => 'Mata uang harus diisi', 'currency.max' => 'Mata uang maksimal 3 karakter', 'is_active.in' => 'Status aktif harus 0 atau 1', ]); // Check if price already exists for this work-dealer combination (including soft deleted) $existingPrice = WorkDealerPrice::withTrashed() ->where('work_id', $request->work_id) ->where('dealer_id', $request->dealer_id) ->first(); // Also check for active records to prevent duplicates $activePrice = WorkDealerPrice::where('work_id', $request->work_id) ->where('dealer_id', $request->dealer_id) ->where('id', '!=', $existingPrice ? $existingPrice->id : 0) ->first(); if ($activePrice) { return response()->json([ 'status' => 422, 'message' => 'Harga untuk dealer ini sudah ada. Silakan edit harga yang sudah ada.' ], 422); } // Use database transaction to prevent race conditions DB::beginTransaction(); try { if ($existingPrice) { if ($existingPrice->trashed()) { // Restore soft deleted record and update $existingPrice->restore(); } // Update existing price $existingPrice->update([ 'price' => $request->price, 'currency' => $request->currency, 'is_active' => $request->has('is_active') ? (bool)$request->is_active : true, ]); $price = $existingPrice; $message = 'Harga berhasil diperbarui'; } else { // Create new price $price = WorkDealerPrice::create([ 'work_id' => $request->work_id, 'dealer_id' => $request->dealer_id, 'price' => $request->price, 'currency' => $request->currency, 'is_active' => $request->has('is_active') ? (bool)$request->is_active : true, ]); $message = 'Harga berhasil disimpan'; } DB::commit(); return response()->json([ 'status' => 200, 'data' => $price, 'message' => $message ]); } catch (\Exception $e) { DB::rollback(); throw $e; } } catch (\Illuminate\Validation\ValidationException $e) { return response()->json([ 'status' => 422, 'message' => 'Validasi gagal', 'errors' => $e->errors() ], 422); } catch (\Illuminate\Database\QueryException $e) { // Handle unique constraint violation if ($e->getCode() == 23000) { return response()->json([ 'status' => 422, 'message' => 'Harga untuk dealer ini sudah ada. Silakan edit harga yang sudah ada.' ], 422); } return response()->json([ 'status' => 500, 'message' => 'Terjadi kesalahan database: ' . $e->getMessage() ], 500); } catch (\Exception $e) { return response()->json([ 'status' => 500, 'message' => 'Terjadi kesalahan: ' . $e->getMessage() ], 500); } } /** * Show the form for editing the specified price */ public function edit($id) { $price = WorkDealerPrice::with(['work', 'dealer'])->findOrFail($id); return response()->json([ 'status' => 200, 'data' => $price, 'message' => 'Data harga berhasil diambil' ]); } /** * Update the specified price */ public function update(Request $request, $id) { $request->validate([ 'price' => 'required|numeric|min:0', 'currency' => 'required|string|max:3', 'is_active' => 'boolean', ]); $price = WorkDealerPrice::findOrFail($id); $price->update($request->all()); return response()->json([ 'status' => 200, 'message' => 'Harga berhasil diperbarui' ]); } /** * Remove the specified price */ public function destroy($id) { try { $price = WorkDealerPrice::findOrFail($id); $price->delete(); // Soft delete return response()->json([ 'status' => 200, 'message' => 'Harga berhasil dihapus' ]); } catch (\Exception $e) { return response()->json([ 'status' => 500, 'message' => 'Terjadi kesalahan saat menghapus harga: ' . $e->getMessage() ], 500); } } /** * Get price for specific work and dealer */ public function getPrice(Request $request) { $request->validate([ 'work_id' => 'required|exists:works,id', 'dealer_id' => 'required|exists:dealers,id', ]); $price = WorkDealerPrice::getPriceForWorkAndDealer( $request->work_id, $request->dealer_id ); return response()->json([ 'status' => 200, 'data' => $price, 'message' => $price ? 'Harga ditemukan' : 'Harga tidak ditemukan' ]); } /** * Toggle status of a price */ public function toggleStatus(Request $request, Work $work) { try { $request->validate([ 'dealer_id' => 'required|exists:dealers,id', 'is_active' => 'required|in:0,1,true,false', ], [ 'dealer_id.required' => 'ID dealer harus diisi', 'dealer_id.exists' => 'Dealer tidak ditemukan', 'is_active.required' => 'Status aktif harus diisi', 'is_active.in' => 'Status aktif harus 0, 1, true, atau false', ]); // Convert string values to boolean $isActive = filter_var($request->is_active, FILTER_VALIDATE_BOOLEAN); // Find existing price (including soft deleted) $existingPrice = WorkDealerPrice::withTrashed() ->where('work_id', $work->id) ->where('dealer_id', $request->dealer_id) ->first(); if (!$existingPrice) { // Create new record with default price 0 if no record exists $existingPrice = WorkDealerPrice::create([ 'work_id' => $work->id, 'dealer_id' => $request->dealer_id, 'price' => 0, 'currency' => 'IDR', 'is_active' => $isActive, ]); } else { // Restore if soft deleted if ($existingPrice->trashed()) { $existingPrice->restore(); } // Update status $existingPrice->update([ 'is_active' => $isActive ]); } return response()->json([ 'status' => 200, 'data' => $existingPrice, 'message' => 'Status berhasil diubah menjadi ' . ($isActive ? 'Aktif' : 'Nonaktif') ]); } catch (\Illuminate\Validation\ValidationException $e) { return response()->json([ 'status' => 422, 'message' => 'Validasi gagal', 'errors' => $e->errors() ], 422); } catch (\Exception $e) { return response()->json([ 'status' => 500, 'message' => 'Terjadi kesalahan: ' . $e->getMessage() ], 500); } } /** * Bulk create prices for a work */ public function bulkCreate(Request $request, Work $work) { $request->validate([ 'prices' => 'required|array', 'prices.*.dealer_id' => 'required|exists:dealers,id', 'prices.*.price' => 'required|numeric|min:0', 'prices.*.currency' => 'required|string|max:3', ]); DB::beginTransaction(); try { foreach ($request->prices as $priceData) { // Check if price already exists $existingPrice = WorkDealerPrice::where('work_id', $work->id) ->where('dealer_id', $priceData['dealer_id']) ->first(); if ($existingPrice) { // Update existing price $existingPrice->update([ 'price' => $priceData['price'], 'currency' => $priceData['currency'], 'is_active' => true, ]); } else { // Create new price WorkDealerPrice::create([ 'work_id' => $work->id, 'dealer_id' => $priceData['dealer_id'], 'price' => $priceData['price'], 'currency' => $priceData['currency'], 'is_active' => true, ]); } } DB::commit(); return response()->json([ 'status' => 200, 'message' => 'Harga berhasil disimpan' ]); } catch (\Exception $e) { DB::rollback(); return response()->json([ 'status' => 500, 'message' => 'Terjadi kesalahan: ' . $e->getMessage() ], 500); } } }