stockService = $stockService; } public function index() { $work_works = Work::leftJoin('categories as c', 'c.id', '=', 'works.category_id') ->select('c.name as category_name', 'works.*') ->where('c.name', 'LIKE', '%kerja%') ->orderBy('works.name', 'asc') ->get(); $wash_work = Work::leftJoin('categories as c', 'c.id', '=', 'works.category_id')->select('c.name as category_name', 'works.*')->where('c.name', 'LIKE', '%cuci%')->first(); $user_sas = User::where('role_id', 4)->where('dealer_id', Auth::user()->dealer_id)->get(); $count_transaction_users = Transaction::where("user_id", Auth::user()->id)->count(); $count_transaction_dealers = Transaction::leftJoin('users', 'users.id', '=', 'transactions.user_id')->where('users.dealer_id', Auth::user()->dealer_id)->count(); $mechanic = User::leftJoin('dealers as d', 'd.id', '=', 'users.dealer_id') ->select('d.name as dealer_name', 'd.id as dealer_id', 'users.name', 'users.id', 'users.role', 'users.email', 'd.dealer_code', 'd.address') ->where('users.id', Auth::user()->id)->first(); $now = Carbon::now()->translatedFormat('d F Y'); // Get products with stock based on user role $products = Product::with(['stocks' => function($query) { $query->where('dealer_id', Auth::user()->dealer_id); }, 'stocks.dealer']) ->where('active', true) ->get(); // Get KPI data for current user using KPI service $kpiService = app(\App\Services\KpiService::class); // Auto-calculate current month KPI achievement including claimed transactions $kpiService->calculateKpiAchievementWithClaims(Auth::user()); $kpiSummary = $kpiService->getKpiSummaryWithClaims(Auth::user()); // Get current month period name $currentMonthName = now()->translatedFormat('F Y'); $kpiData = [ 'target' => $kpiSummary['current_target'] ? $kpiSummary['current_target']->target_value : 0, 'actual' => $kpiSummary['current_achievement'] ? $kpiSummary['current_achievement']->actual_value : 0, 'percentage' => $kpiSummary['current_percentage'], 'status' => $kpiSummary['current_achievement'] ? $kpiSummary['current_achievement']->status : 'pending', 'status_color' => $kpiSummary['current_achievement'] ? $kpiSummary['current_achievement']->status_color : 'secondary', 'period' => $currentMonthName, 'has_target' => $kpiSummary['current_target'] ? true : false ]; return view('transaction.index', compact('now', 'wash_work', 'work_works', 'user_sas', 'count_transaction_users', 'count_transaction_dealers', 'mechanic', 'products', 'kpiData')); } public function workcategory($category_id) { $works = Work::where('category_id', $category_id) ->orderBy('name', 'asc') ->get(); $response = [ "message" => "get work category successfully", "data" => $works, "status" => 200 ]; return response()->json($response); } public function lists(Request $request) { if(!isset($request->date_start)) { $request['date_start'] = date('Y-m-d'); } if(!isset($request->date_end)) { $request['date_end'] = date('Y-m-d'); } $transaction_dealers = Transaction::leftJoin('users', 'users.id', '=', 'transactions.user_id') ->leftJoin('users as sa', 'sa.id', '=', 'transactions.user_sa_id') ->leftJoin('works as w', 'w.id', '=', 'transactions.work_id') ->leftJoin('categories as cat', 'cat.id', '=', 'w.category_id') ->select('transactions.id as transaction_id', 'transactions.status', 'transactions.user_id as user_id', 'transactions.user_sa_id as user_sa_id', 'users.name as username', 'sa.name as sa_name', 'cat.name as category_name', 'w.name as workname', 'transactions.qty as qty', 'transactions.date as date', 'transactions.police_number as police_number', 'transactions.warranty as warranty', 'transactions.spk as spk') ->whereNull('transactions.deleted_at') ->where('users.dealer_id', Auth::user()->dealer_id); $transaction_works = Work::select('id', 'name', 'shortname')->whereHas('transactions', function($q) { return $q->whereNull('deleted_at')->whereDate('date', '=', date('Y-m-d'))->where('dealer_id', Auth::user()->dealer_id); })->get(); $tm1 = []; foreach($transaction_works as $index => $work) { $transaction_sas = Transaction::leftJoin('users as sa', 'sa.id', '=', 'transactions.user_sa_id') ->select(DB::raw('SUM(transactions.qty) as qty'), 'sa.name as sa_name') ->whereNull('transactions.deleted_at') ->where('sa.dealer_id', Auth::user()->dealer_id) ->where('work_id', $work->id) ->whereDate('transactions.date', '=', date('Y-m-d'))->groupBy('transactions.user_sa_id')->get(); // Initialize data array for this work $tm1[$work['shortname']]['data'] = []; $daily_total = 0; foreach($transaction_sas as $sa) { $tm1[$work['shortname']]['data'][] = $sa['sa_name'].":".$sa['qty']; $daily_total += $sa['qty']; } // Add daily total even if no data if (empty($tm1[$work['shortname']]['data'])) { $tm1[$work['shortname']]['data'][] = "Tidak ada data:0"; } // Remove monthly data section since this is daily report // $month_share_data = Transaction::select(DB::raw('SUM(qty) as qty'), 'u.name') // ->join('users AS u', 'u.id', '=', 'transactions.user_sa_id') // ->where('transactions.dealer_id', Auth::user()->dealer->id) // ->whereMonth('date', date('m')) // ->whereYear('date', date('Y')) // ->where('work_id', $work->id) // ->groupBy('user_sa_id') // ->get(); // Remove the period title since this is for daily report, not monthly // $tm1[$work['shortname']]['total_title'] = "*[PERIODE 1 - ". Carbon::now()->translatedFormat('d F Y') ."]*\n\n"; // $sum_month_share_trx = 0; // $tm_month = []; // foreach($month_share_data as $m_trx) { // $tm_month[] = $m_trx->name.":".$m_trx->qty." Unit\n"; // $sum_month_share_trx += $m_trx->qty; // } // $tm1[$work['shortname']]['total_body'] = $tm_month; // $tm1[$work['shortname']]['total_total'] = "*TOTAL : ". $sum_month_share_trx." Unit*"; } if(isset($request->date_start)) { $transaction_dealers = $transaction_dealers->where('transactions.date', '>=', date('Y-m-d', strtotime($request->date_start))); } if(isset($request->date_end)){ $transaction_dealers = $transaction_dealers->where('transactions.date', '<=', date('Y-m-d', strtotime($request->date_end))); } $transaction_dealers = $transaction_dealers->orderBy('date', 'DESC')->paginate(6); $date_start = $request->date_start; $date_end = $request->date_end; $transaction_mechanics = ["today_date"=> Carbon::now()->translatedFormat('d F Y'), "data"=>$tm1]; $mechanic = User::leftJoin('dealers as d', 'd.id', '=', 'users.dealer_id') ->select('d.name as dealer_name', 'users.name', 'users.id', 'users.role', 'users.email', 'd.dealer_code', 'd.address') ->where('users.id', Auth::user()->id)->first(); $sas = User::where('role_id', 4)->get(); $dealers = Dealer::all(); $works = Work::all(); // Get KPI data for current user using KPI service $kpiService = app(\App\Services\KpiService::class); // Auto-calculate current month KPI achievement including claimed transactions $kpiService->calculateKpiAchievementWithClaims(Auth::user()); $kpiSummary = $kpiService->getKpiSummaryWithClaims(Auth::user()); // Get current month period name $currentMonthName = now()->translatedFormat('F Y'); $kpiData = [ 'target' => $kpiSummary['current_target'] ? $kpiSummary['current_target']->target_value : 0, 'actual' => $kpiSummary['current_achievement'] ? $kpiSummary['current_achievement']->actual_value : 0, 'percentage' => $kpiSummary['current_percentage'], 'status' => $kpiSummary['current_achievement'] ? $kpiSummary['current_achievement']->status : 'pending', 'status_color' => $kpiSummary['current_achievement'] ? $kpiSummary['current_achievement']->status_color : 'secondary', 'period' => $currentMonthName, 'has_target' => $kpiSummary['current_target'] ? true : false ]; return view('transaction.lists', compact('transaction_dealers', 'transaction_mechanics', 'mechanic', 'sas', 'dealers', 'works', 'date_start', 'date_end', 'kpiData')); } public function cmp($a, $b){ $key = 'work_id'; if($a[$key] > $b[$key]){ return 1; }else if($a[$key] < $b[$key]){ return -1; } return 0; } public function cmp2($a, $b){ $key = 'id'; if($a[$key] > $b[$key]){ return 1; }else if($a[$key] < $b[$key]){ return -1; } return 0; } public function recap_old(Request $request) { $id = Auth::user()->dealer_id; $works = Work::all(); $dealer = Dealer::find($id); $works_count = Work::count(); $mechanic = User::leftJoin('dealers as d', 'd.id', '=', 'users.dealer_id') ->select('d.name as dealer_name', 'users.name', 'users.id', 'users.role', 'users.email', 'd.dealer_code', 'd.address') ->where('users.id', Auth::user()->id)->first(); $d = Transaction::leftJoin('works as w', 'w.id', '=', 'transactions.work_id')->select('transactions.*', 'w.name as work_name', 'w.shortname as shortname')->whereNull('transactions.deleted_at')->where('dealer_id', $id); if(isset($request->date_start)) { $d = $d->where('transactions.date', '>=', date('Y-m-d', strtotime($request->date_start))); } if(isset($request->date_end)){ $d = $d->where('transactions.date', '<=', date('Y-m-d', strtotime($request->date_end))); } $d = $d->get()->toArray(); $works2 = []; foreach($d as $d2) { $w1 = Work::find($d2['work_id']); $works2[$d2['work_id']] = $w1; } usort($works2, array($this, 'cmp2')); $works = $works2; $dw = []; foreach($d as $dw2) { $dw[$dw2['date']][] = $dw2; } $works_count = count($works); $dw9 = []; $sharedw = []; foreach($dw as $key => $dw3) { $dw5 = []; foreach($dw3 as $dw4) { if(array_key_exists($dw4['work_id'], $dw5)) { $dw5[$dw4['work_id']]['qty'] += $dw4['qty']; }else{ $dw5[$dw4['work_id']] = $dw4; } } usort($dw5, array($this, 'cmp')); $dw7 = []; foreach($dw5 as $dw6) { $dw7[$dw6['work_id']] = $dw6; $sharedw[$key][] = [ "work_id" => $dw6['work_id'], "shortname" => $dw6['shortname'], "qty" => $dw6['qty'], "date" => date('d/m/Y', strtotime($dw6['date'])), ]; } $dw8 = []; for($i = 0; $i < count($works2); $i++) { if(array_key_exists($works2[$i]['id'], $dw7)) { $dw8[$works2[$i]['id']] = [ "work_id" => $dw7[$works2[$i]['id']]['work_id'], "qty" => $dw7[$works2[$i]['id']]['qty'], "work_name" => $dw7[$works2[$i]['id']]['work_name'], "date" => date('d/m/Y', strtotime($dw7[$works2[$i]['id']]['date'])) ]; }else{ $dw8[$works2[$i]['id']] = [ "work_id" => $works2[$i]['id'], "qty" => 0, "work_name" => '-', "date" => '-' ]; } } $dw9[$key] = [ 'date' => $key, 'works' => $dw8 ]; } // $works = $trxs = $dw9; $dwd = []; foreach($d as $dwd2) { $dwd[$dwd2['user_sa_id']][] = $dwd2; } $dwd9 = []; foreach($dwd as $key2 => $dwd3) { $dwd5 = []; foreach($dwd3 as $dwd4) { if(array_key_exists($dwd4['work_id'], $dwd5)) { $dwd5[$dwd4['work_id']]['qty'] += $dwd4['qty']; }else{ $dwd5[$dwd4['work_id']] = $dwd4; } } usort($dwd5, array($this, 'cmp')); $dwd7 = []; foreach($dwd5 as $dwd6) { $dwd7[$dwd6['work_id']] = $dwd6; } $dwd8 = []; for($i = 0; $i < count($works); $i++) { if(array_key_exists($works[$i]['id'], $dwd7)) { $dwd8[$works[$i]['id']] = [ "work_id" => $dwd7[$works[$i]['id']]['work_id'], "qty" => $dwd7[$works[$i]['id']]['qty'], "work_name" => $dwd7[$works[$i]['id']]['work_name'], "date" => date('d/m/Y', strtotime($dwd7[$works[$i]['id']]['date'])) ]; }else{ $dwd8[$works[$i]['id']] = [ "work_id" => $works[$i]['id'], "qty" => 0, "work_name" => '-', "date" => '-' ]; } } $sa_name = User::find($key2); $dwd9[$sa_name->name] = [ 'sa_name' => $sa_name->name, 'works' => $dwd8 ]; } $dealer_trxs = $dwd9; return view('transaction.recap_old', compact('works', 'works_count', 'trxs', 'dealer_trxs','dealer', 'sharedw', 'mechanic')); } private function array_value_recursive($key, array $arr){ $val = array(); array_walk_recursive($arr, function($v, $k) use($key, &$val){ if($k == $key) array_push($val, $v); }); return $val; } public function recap2(Request $request) { if(!isset($request->month)) { $request['month'] = date('m'); } $id = Auth::user()->dealer_id; $works = Work::select('id', 'name', 'shortname')->whereHas('transactions', function($q) use($request, $id) { if(isset($request->month)) { return $q->whereNull('deleted_at')->whereMonth('date', '=', $request->month)->whereYear('date', date('Y'))->where('dealer_id', $id); } })->get(); $sas = User::select('id', 'name')->whereHas('sa_transactions', function($q) use($request, $id) { if(isset($request->month)) { return $q->whereNull('deleted_at')->whereMonth('date', '=', $request->month)->whereYear('date', date('Y'))->where('dealer_id', $id); } })->get(); $dealer = Dealer::find($id); $mechanic = User::leftJoin('dealers as d', 'd.id', '=', 'users.dealer_id') ->select('d.name as dealer_name', 'users.name', 'users.id', 'users.role', 'users.email', 'd.dealer_code', 'd.address') ->where('users.id', Auth::user()->id)->first(); $dates = Transaction::select(DB::raw('DATE(`date`) as date'))->whereNull('deleted_at')->where('dealer_id', $id)->whereMonth('date', $request->month)->whereYear('date', date('Y'))->groupBy(DB::raw('DATE(`date`)'))->get()->toArray(); $dates = $this->array_value_recursive('date', $dates); $month_trxs = []; $month_trxs_total = []; $yesterday_month_trxs_total = []; foreach($works as $work1) { $prev_mth_start = date('Y-m-d', strtotime(date('Y-'. $request->month .'-1')." -1 month")); $prev_mth = explode('-', $prev_mth_start); $prev_mth_end = $prev_mth[0].'-'.$prev_mth[1].'-'.date('d'); $yesterday_month_trx = Transaction::whereNull('deleted_at')->where('work_id', $work1->id)->where('dealer_id', $id)->whereDate('date', '>=', $prev_mth_start)->whereDate('date', '<=', $prev_mth_end)->sum('qty'); if(array_key_exists($work1->id, $yesterday_month_trxs_total)) { $yesterday_month_trxs_total[$work1->id] += $yesterday_month_trx; }else{ $yesterday_month_trxs_total[$work1->id] = $yesterday_month_trx; } } if($dates) { foreach($dates as $key => $date) { $date_works = []; $share_works = []; foreach ($works as $key2 => $work) { $d = Transaction::whereNull('deleted_at')->where('work_id', $work->id)->where('dealer_id', $id)->whereDate('date', $date); if(isset($request->month)) { $d = $d->whereMonth('date', '=', $request->month)->whereYear('date', date('Y')); } $d = $d->sum('qty'); if($d) { if(array_key_exists($work->id, $month_trxs_total)) { $month_trxs_total[$work->id] += $d; }else{ $month_trxs_total[$work->id] = $d; } $date_works[] = [ 'work_id' => $work->id, 'work_name' => $work->name, 'shortname' => $work->shortname, 'date' => $date, 'qty' => $d, ]; }else{ $date_works[] = [ 'work_id' => $work->id, 'work_name' => $work->name, 'shortname' => $work->shortname, 'date' => $date, 'qty' => 0, ]; } } $month_trxs[] = [ 'date' => date('d/m/Y', strtotime($date)), 'works' => $date_works ]; } } $trxs = []; foreach($sas as $key => $sa) { $sa_works = []; foreach ($works as $key2 => $work) { $d = Transaction::whereNull('deleted_at')->where('user_sa_id', $sa->id)->where('work_id', $work->id)->where('dealer_id', $id); if(isset($request->month)) { $d = $d->whereMonth('date', '=', $request->month)->whereYear('date', date('Y')); $month = $request->month; } $d = $d->sum('qty'); if($d) { $sa_works[] = [ 'work_id' => $work->id, 'work_name' => $work->name, 'user_sa_id' => $sa->id, 'qty' => $d, ]; }else{ $sa_works[] = [ 'work_id' => $work->id, 'work_name' => $work->name, 'user_sa_id' => $sa->id, 'qty' => 0, ]; } } $trxs[] = [ 'user_sa_id' => $sa->id, 'sa_name' => $sa->name, 'works' => $sa_works ]; } $sa_names = []; $trx_data = []; foreach($trxs as $trx) { $sa_names[] = $trx['sa_name']; $work_data2 = []; foreach($trx['works'] as $work_data) { if(array_key_exists($work_data['work_name'], $trx_data)) { $trx_data[$work_data['work_name']]['qty'][] = $work_data['qty']; }else{ $trx_data[$work_data['work_name']] = [ 'work_name' => $work_data['work_name'], 'qty' => [$work_data['qty']] ]; } } } $sa_names = json_encode($sa_names); $trx_data = json_encode(array_values($trx_data)); $works_count = count($works); $share = $month_trxs; $month = $request->month; dd($share); return view('transaction.recap', compact('month_trxs_total', 'yesterday_month_trxs_total', 'month', 'trx_data', 'sa_names', 'works', 'works_count', 'trxs', 'month_trxs','dealer', 'share', 'mechanic')); } public function recap(Request $request) { if(!isset($request->month)) { $request['month'] = date('m'); } if(!isset($request->year)) { $request['year'] = date('Y'); } $id = Auth::user()->dealer_id; $works = Work::select('id', 'name', 'shortname')->whereHas('transactions', function($q) use($request, $id) { if(isset($request->month)) { return $q->whereNull('deleted_at')->whereMonth('date', '=', $request->month)->whereYear('date', $request->year)->where('dealer_id', $id); } })->get(); $sas = User::select('id', 'name')->whereHas('sa_transactions', function($q) use($request, $id) { if(isset($request->month)) { return $q->whereNull('deleted_at')->whereMonth('date', '=', $request->month)->whereYear('date', $request->year)->where('dealer_id', $id); } })->get(); $dealer = Dealer::find($id); $mechanic = User::leftJoin('dealers as d', 'd.id', '=', 'users.dealer_id') ->select('d.name as dealer_name', 'users.name', 'users.id', 'users.role', 'users.email', 'd.dealer_code', 'd.address') ->where('users.id', Auth::user()->id)->first(); $dates = Transaction::select(DB::raw('DATE(`date`) as date'))->whereNull('deleted_at')->where('dealer_id', $id)->whereMonth('date', $request->month)->whereYear('date', $request->year)->groupBy(DB::raw('DATE(`date`)'))->get()->toArray(); // print_r($dates);die; $dates = $this->array_value_recursive('date', $dates); $month_trxs = []; $month_trxs_total = []; $yesterday_month_trxs_total = []; foreach($works as $work1) { $prev_mth_start = date('Y-m-d', strtotime(date($request->year.'-'. $request->month .'-1')." -1 month")); $prev_mth = explode('-', $prev_mth_start); if($request->month == date('m')) { $prev_mth_end = $prev_mth[0].'-'.$prev_mth[1].'-'.date('d'); }else{ $prev_mth_end = $prev_mth[0].'-'.$prev_mth[1].'-'.date('t'); } // dd($prev_mth_end); $yesterday_month_trx = Transaction::whereNull('deleted_at')->where('work_id', $work1->id)->where('dealer_id', $id)->whereDate('date', '>=', $prev_mth_start)->whereDate('date', '<=', $prev_mth_end)->sum('qty'); if(array_key_exists($work1->id, $yesterday_month_trxs_total)) { $yesterday_month_trxs_total[$work1->id] += $yesterday_month_trx; }else{ $yesterday_month_trxs_total[$work1->id] = $yesterday_month_trx; } } if($dates) { foreach($dates as $key => $date) { $date_works = []; $share_works = []; foreach ($works as $key2 => $work) { $d = Transaction::whereNull('deleted_at')->where('work_id', $work->id)->where('dealer_id', $id)->whereDate('date', $date); if(isset($request->month)) { $d = $d->whereMonth('date', '=', $request->month)->whereYear('date', $request->year); } $d = $d->sum('qty'); if($d) { if(array_key_exists($work->id, $month_trxs_total)) { $month_trxs_total[$work->id] += $d; }else{ $month_trxs_total[$work->id] = $d; } $date_works[] = [ 'work_id' => $work->id, 'work_name' => $work->name, 'shortname' => $work->shortname, 'date' => $date, 'qty' => $d, ]; }else{ $date_works[] = [ 'work_id' => $work->id, 'work_name' => $work->name, 'shortname' => $work->shortname, 'date' => $date, 'qty' => 0, ]; } } $month_trxs[] = [ 'date' => date('d/m/Y', strtotime($date)), 'works' => $date_works ]; } } $this_month_trxs = Transaction::select(DB::raw('SUM(qty) as qty'), 'u.name')->join('users AS u', 'u.id', '=', 'transactions.user_sa_id')->whereNull('transactions.deleted_at')->where('transactions.dealer_id', $id)->whereMonth('date', date('m'))->whereYear('date', $request->year)->groupBy('user_sa_id')->get(); $today_trxs = Transaction::select(DB::raw('SUM(qty) as qty'), 'u.name')->join('users AS u', 'u.id', '=', 'transactions.user_sa_id')->whereNull('transactions.deleted_at')->where('transactions.dealer_id', $id)->whereDate('date', date('Y-m-d'))->groupBy('user_sa_id')->get(); $trxs = []; foreach($sas as $key => $sa) { $sa_works = []; foreach ($works as $key2 => $work) { $d = Transaction::whereNull('deleted_at')->where('user_sa_id', $sa->id)->where('work_id', $work->id)->where('dealer_id', $id); if(isset($request->month)) { $d = $d->whereMonth('date', '=', $request->month)->whereYear('date', $request->year); $month = $request->month; } $d = $d->sum('qty'); if($d) { $sa_works[] = [ 'work_id' => $work->id, 'work_name' => $work->name, 'user_sa_id' => $sa->id, 'qty' => $d, ]; }else{ $sa_works[] = [ 'work_id' => $work->id, 'work_name' => $work->name, 'user_sa_id' => $sa->id, 'qty' => 0, ]; } } $trxs[] = [ 'user_sa_id' => $sa->id, 'sa_name' => $sa->name, 'works' => $sa_works ]; } $sa_names = []; $trx_data = []; foreach($trxs as $trx) { $sa_names[] = $trx['sa_name']; $work_data2 = []; foreach($trx['works'] as $work_data) { if(array_key_exists($work_data['work_name'], $trx_data)) { $trx_data[$work_data['work_name']]['qty'][] = $work_data['qty']; }else{ $trx_data[$work_data['work_name']] = [ 'work_name' => $work_data['work_name'], 'qty' => [$work_data['qty']] ]; } } } // dd($works); // dd([$month_trxs_total, $yesterday_month_trxs_total]); $final_month_trxs_total = []; $final_yesterday_month_trxs_total = []; foreach($works as $work1) { $final_month_trxs_total[$work1->id] = $month_trxs_total[$work1->id]; $final_yesterday_month_trxs_total[$work1->id] = $yesterday_month_trxs_total[$work1->id]; } // dd([$final_month_trxs_total, $final_yesterday_month_trxs_total]); $month_trxs_total = array_values($final_month_trxs_total); $yesterday_month_trxs_total = array_values($final_yesterday_month_trxs_total); $totals = []; for($i = 0; $i < count($month_trxs_total); $i++) { $totals[] = [ "prev" => $yesterday_month_trxs_total[$i], "now" => $month_trxs_total[$i], ]; } $sa_names = json_encode($sa_names); $trx_data = json_encode(array_values($trx_data)); $works_count = count($works); $share = ["this_month_trxs" => $this_month_trxs, "today_trxs" => $today_trxs, 'today_date' => Carbon::now()->translatedFormat('d F Y')]; $month = $request->month; $year = $request->year; return view('transaction.recap', compact('totals', 'month', 'year', 'trx_data', 'sa_names', 'works', 'works_count', 'trxs', 'month_trxs','dealer', 'share', 'mechanic')); } public function destroy($id) { DB::beginTransaction(); try { $transaction = Transaction::find($id); if (!$transaction) { return redirect()->back()->withErrors(['error' => 'Transaksi tidak ditemukan']); } // Restore stock before deleting transaction $this->stockService->restoreStockForTransaction($transaction); // Delete the transaction $transaction->delete(); DB::commit(); return redirect()->back()->with('success', 'Transaksi berhasil dihapus dan stock telah dikembalikan'); } catch (Exception $e) { DB::rollback(); return redirect()->back()->withErrors(['error' => 'Gagal menghapus transaksi: ' . $e->getMessage()]); } } public function store(Request $request) { // Handle different form types (work vs wash) $isWashForm = $request->form === 'wash'; $validWorkIds = []; $validQuantities = []; $validPairs = []; if ($isWashForm) { // For wash form, work_id and quantity are already fixed $validWorkIds = $request->work_id; $validQuantities = $request->quantity; // Create pairs for wash form if (is_array($request->work_id) && is_array($request->quantity)) { for ($i = 0; $i < count($request->work_id); $i++) { $validPairs[] = [ 'work_id' => $request->work_id[$i], 'quantity' => $request->quantity[$i], 'index' => $i ]; } } } else { // For work form, filter out empty work/quantity pairs before validation if ($request->work_id && $request->quantity) { for ($i = 0; $i < count($request->work_id); $i++) { $workId = $request->work_id[$i] ?? null; $quantity = $request->quantity[$i] ?? null; // Only include pairs where both work_id and quantity are filled if (!empty($workId) && !empty($quantity) && $quantity > 0) { $validWorkIds[] = $workId; $validQuantities[] = $quantity; $validPairs[] = [ 'work_id' => $workId, 'quantity' => $quantity, 'index' => $i ]; } } } // Check if at least one valid pair exists (only for work form) if (empty($validPairs)) { return redirect()->back() ->withErrors(['error' => 'Minimal pilih satu pekerjaan dan isi quantity-nya']) ->withInput(); } } // Update request with filtered data for validation $request->merge([ 'work_id' => $validWorkIds, 'quantity' => $validQuantities ]); $request->validate([ 'work_id.*' => ['required', 'integer', 'exists:works,id'], 'quantity.*' => ['required', 'integer', 'min:1'], 'spk_no' => ['required', 'string', 'min:1', function($attribute, $value, $fail) use($request) { // Handle date format conversion safely for validation if (strpos($request->date, '/') !== false) { $dateParts = explode('/', $request->date); if (count($dateParts) === 3) { $date = $dateParts[2].'-'.$dateParts[0].'-'.$dateParts[1]; } else { $fail('Format tanggal tidak valid'); return; } } else { $date = $request->date; } if(!$request->work_id) { $fail('Pekerjaan harus diisi'); }else{ $error_work = ''; foreach($request->work_id as $work_id) { $check = Transaction::with(['work'])->where('work_id', $work_id)->where('date', $date)->where('spk', $value)->where('police_number', $request->police_number)->orderBy('id', 'DESC')->whereDate('created_at', date('Y-m-d'))->limit(1)->first(); if($check) { $error_work .= $check->work->name.', '; } } if($error_work) { $fail('SPK ini sudah digunakan untuk pekerjaan '. $error_work .' sebelumnya'); } } }], 'police_number' => ['required', 'string', 'min:1', function($attribute, $value, $fail) use($request) { // Handle date format conversion safely for validation if (strpos($request->date, '/') !== false) { $dateParts = explode('/', $request->date); if (count($dateParts) === 3) { $date = $dateParts[2].'-'.$dateParts[0].'-'.$dateParts[1]; } else { $fail('Format tanggal tidak valid'); return; } } else { $date = $request->date; } if(!$request->work_id) { $fail('Pekerjaan harus diisi'); }else{ $error_work = ''; foreach($request->work_id as $work_id) { $check = Transaction::with(['work'])->where('work_id', $work_id)->where('date', $date)->where('spk', $request->spk_no)->where('police_number', $value)->orderBy('id', 'DESC')->whereDate('created_at', date('Y-m-d'))->limit(1)->first(); if($check) { $error_work .= $check->work->name.', '; } } if($error_work) { $fail('No Polisi ini sudah digunakan untuk pekerjaan '. $error_work .' sebelumnya'); } } }], 'warranty' => ['required', 'in:0,1'], 'date' => ['required', 'string', 'min:1', function($attribute, $value, $fail) use($request) { // Handle date format conversion safely for validation if (strpos($value, '/') !== false) { $dateParts = explode('/', $value); if (count($dateParts) === 3) { $date = $dateParts[2].'-'.$dateParts[0].'-'.$dateParts[1]; } else { $fail('Format tanggal tidak valid. Gunakan format MM/DD/YYYY atau YYYY-MM-DD'); return; } } else { $date = $value; } if(!$request->work_id) { $fail('Pekerjaan harus diisi'); }else{ $error_work = ''; foreach($request->work_id as $work_id) { $check = Transaction::with(['work'])->where('work_id', $work_id)->where('date', $date)->where('spk', $request->spk_no)->where('police_number', $request->police_number)->orderBy('id', 'DESC')->whereDate('created_at', date('Y-m-d'))->limit(1)->first(); if($check) { $error_work .= $check->work->name.', '; } } if($error_work) { $fail('Tanggal ini sudah digunakan untuk pekerjaan '. $error_work .' sebelumnya'); } } }], 'category' => ['required'], 'user_sa_id' => ['required', 'integer', 'exists:users,id'], ], [ 'spk_no.required' => 'No. SPK harus diisi', 'spk_no.min' => 'No. SPK tidak boleh kosong', 'police_number.required' => 'No. Polisi harus diisi', 'police_number.min' => 'No. Polisi tidak boleh kosong', 'date.required' => 'Tanggal Pekerjaan harus diisi', 'date.min' => 'Tanggal Pekerjaan tidak boleh kosong', 'warranty.required' => 'Warranty harus dipilih', 'user_sa_id.required' => 'Service Advisor harus dipilih', 'user_sa_id.exists' => 'Service Advisor yang dipilih tidak valid', 'work_id.*.required' => 'Pekerjaan yang dipilih harus valid', 'work_id.*.exists' => 'Pekerjaan yang dipilih tidak ditemukan', 'quantity.*.required' => 'Quantity harus diisi untuk setiap pekerjaan yang dipilih', 'quantity.*.min' => 'Quantity minimal 1', ]); // Handle date format conversion safely $dateValue = $request->date; if (strpos($dateValue, '/') !== false) { // If date is in MM/DD/YYYY format, convert to Y-m-d $dateParts = explode('/', $dateValue); if (count($dateParts) === 3) { $request['date'] = $dateParts[2].'-'.$dateParts[0].'-'.$dateParts[1]; } else { // Invalid date format, use as is $request['date'] = $dateValue; } } else { // Date is already in Y-m-d format or other format, use as is $request['date'] = $dateValue; } // Stock checking removed - allow negative stock DB::beginTransaction(); try { $transactions = []; $data = []; // Create transaction records using filtered valid pairs foreach($validPairs as $pair) { $transactionData = [ "user_id" => $request->mechanic_id, "dealer_id" => $request->dealer_id, "form" => $request->form, "work_id" => $pair['work_id'], "qty" => $pair['quantity'], "spk" => $request->spk_no, "police_number" => $request->police_number, "warranty" => $request->warranty, "user_sa_id" => $request->user_sa_id, "date" => $request->date, "status" => 0, // pending (0) - Mark as pending initially "created_at" => date('Y-m-d H:i:s'), "updated_at" => date('Y-m-d H:i:s'), "claimed_at" => Auth::user()->role_id == 3 ? now() : null, "claimed_by" => Auth::user()->role_id == 3 ? Auth::user()->id : null, ]; $data[] = $transactionData; } // Insert all transactions Transaction::insert($data); // Get the created transactions for stock reduction $createdTransactions = Transaction::where('spk', $request->spk_no) ->where('police_number', $request->police_number) ->where('date', $request->date) ->where('dealer_id', $request->dealer_id) ->get(); // Reduce stock for each transaction foreach ($createdTransactions as $transaction) { $this->stockService->reduceStockForTransaction($transaction); } // Recalculate KPI achievement after creating transactions $kpiService = app(\App\Services\KpiService::class); $kpiService->calculateKpiAchievementWithClaims(Auth::user()); DB::commit(); return redirect()->back()->with('success', 'Berhasil input pekerjaan dan stock telah dikurangi otomatis'); } catch (Exception $e) { DB::rollback(); return redirect()->back() ->withErrors(['error' => 'Gagal menyimpan transaksi: ' . $e->getMessage()]) ->withInput(); } } public function edit($id) { $transaction = Transaction::find($id); $response = [ 'data' => $transaction, 'status' => 200, 'message' => 'get data successfully' ]; return response()->json($response); } public function update(Request $request, $id) { Transaction::find($id)->update([ "spk" => $request->spk, "date" => $request->date, "police_number" => $request->police_number, "work_id" => $request->work_id, "qty" => $request->qty, "warranty" => $request->warranty, "user_sa_id" => $request->sa_id, ]); $response = [ "status" => 200, "message" => "Data updated successfully" ]; return response()->json($response); } /** * Check stock availability for work at dealer */ public function checkStockAvailability(Request $request) { $request->validate([ 'work_id' => 'required|exists:works,id', 'dealer_id' => 'required|exists:dealers,id', 'quantity' => 'required|integer|min:1' ]); try { $availability = $this->stockService->checkStockAvailability( $request->work_id, $request->dealer_id, $request->quantity ); return response()->json([ 'status' => 200, 'data' => $availability ]); } catch (Exception $e) { return response()->json([ 'status' => 500, 'message' => 'Error checking stock: ' . $e->getMessage() ], 500); } } /** * Get stock prediction for work */ public function getStockPrediction(Request $request) { $request->validate([ 'work_id' => 'required|exists:works,id', 'quantity' => 'required|integer|min:1' ]); try { $prediction = $this->stockService->getStockUsagePrediction( $request->work_id, $request->quantity ); return response()->json([ 'status' => 200, 'data' => $prediction ]); } catch (Exception $e) { return response()->json([ 'status' => 500, 'message' => 'Error getting prediction: ' . $e->getMessage() ], 500); } } /** * Get claim transactions for DataTable - Only for mechanics */ public function getClaimTransactions(Request $request) { // Only allow mechanics to access this endpoint if (Auth::user()->role_id != 3) { return response()->json([ 'draw' => intval($request->input('draw')), 'recordsTotal' => 0, 'recordsFiltered' => 0, 'data' => [] ]); } $request->validate([ 'dealer_id' => 'required|exists:dealers,id' ]); try { $query = Transaction::leftJoin('users', 'users.id', '=', 'transactions.user_id') ->leftJoin('users as sa', 'sa.id', '=', 'transactions.user_sa_id') ->leftJoin('works as w', 'w.id', '=', 'transactions.work_id') ->select([ 'transactions.id', 'transactions.date', 'transactions.spk', 'transactions.police_number', 'transactions.qty', 'transactions.status', 'transactions.claimed_at', 'transactions.claimed_by', 'w.name as work_name', 'sa.name as sa_name', 'users.name as mechanic_name' ]) ->whereNull('transactions.deleted_at') ->where('transactions.dealer_id', $request->dealer_id) ->whereIn('transactions.status', [0, 1]) // Only pending and completed transactions ->orderBy('transactions.date', 'desc'); // Handle DataTables server-side processing $total = $query->count(); // Search functionality if ($request->has('search') && !empty($request->search['value'])) { $searchValue = $request->search['value']; $query->where(function($q) use ($searchValue) { $q->where('transactions.spk', 'like', "%{$searchValue}%") ->orWhere('transactions.police_number', 'like', "%{$searchValue}%") ->orWhere('w.name', 'like', "%{$searchValue}%") ->orWhere('sa.name', 'like', "%{$searchValue}%") ->orWhere('users.name', 'like', "%{$searchValue}%"); }); } $filteredTotal = $query->count(); // Pagination $start = $request->input('start', 0); $length = $request->input('length', 15); $query->skip($start)->take($length); $transactions = $query->get(); $data = []; foreach ($transactions as $transaction) { $data[] = [ 'id' => $transaction->id, 'date' => date('d/m/Y', strtotime($transaction->date)), 'spk' => $transaction->spk, 'police_number' => $transaction->police_number, 'work_name' => $transaction->work_name, 'qty' => number_format($transaction->qty), 'sa_name' => $transaction->sa_name, 'status' => $this->getStatusBadge($transaction->status), 'action' => $this->getActionButtons($transaction), 'claimed_at' => $transaction->claimed_at, 'claimed_by' => $transaction->claimed_by ]; } return response()->json([ 'draw' => intval($request->input('draw')), 'recordsTotal' => $total, 'recordsFiltered' => $filteredTotal, 'data' => $data ]); } catch (Exception $e) { return response()->json([ 'error' => 'Error fetching claim transactions: ' . $e->getMessage() ], 500); } } /** * Get status badge HTML */ private function getStatusBadge($status) { switch ($status) { case 0: // pending return 'Menunggu'; case 1: // completed return 'Closed'; default: return 'Tidak Diketahui'; } } /** * Claim a transaction - Only for mechanics */ public function claim($id) { // Only allow mechanics to claim transactions if (Auth::user()->role_id != 3) { return response()->json([ 'status' => 403, 'message' => 'Hanya mekanik yang dapat mengklaim pekerjaan' ], 403); } try { $transaction = Transaction::whereNull('deleted_at')->find($id); if (!$transaction) { return response()->json([ 'status' => 404, 'message' => 'Transaksi tidak ditemukan' ], 404); } // Check if transaction belongs to current user's dealer if ($transaction->dealer_id !== Auth::user()->dealer_id) { return response()->json([ 'status' => 403, 'message' => 'Anda tidak memiliki akses ke transaksi ini' ], 403); } // Check if transaction can be claimed (pending or completed) if (!in_array($transaction->status, [0, 1])) { // pending (0) and completed (1) return response()->json([ 'status' => 400, 'message' => 'Hanya transaksi yang menunggu atau sudah selesai yang dapat diklaim' ], 400); } // Check if transaction is already claimed if (!empty($transaction->claimed_at) || !empty($transaction->claimed_by)) { return response()->json([ 'status' => 400, 'message' => 'Transaksi ini sudah diklaim sebelumnya' ], 400); } // Update transaction with claim information $transaction->update([ 'claimed_at' => now(), 'claimed_by' => Auth::user()->id ]); // Only recalculate KPI if this is a manual claim (not auto-claimed during creation) // Auto-claimed transactions during creation already have KPI calculated in store method $kpiService = app(\App\Services\KpiService::class); $kpiService->calculateKpiAchievementWithClaims(Auth::user()); return response()->json([ 'status' => 200, 'message' => 'Pekerjaan berhasil diklaim' ]); } catch (Exception $e) { return response()->json([ 'status' => 500, 'message' => 'Gagal mengklaim pekerjaan: ' . $e->getMessage() ], 500); } } /** * Get action buttons HTML for claim transactions - Only for mechanics */ private function getActionButtons($transaction) { $buttons = ''; // Only show buttons for mechanics if (Auth::user()->role_id == 3) { // Claim button - show only if not claimed yet if (empty($transaction->claimed_at) && empty($transaction->claimed_by)) { $buttons .= ''; } else { if($transaction->claimed_by == Auth::user()->id) { // Check if precheck exists $precheck = \App\Models\Precheck::where('transaction_id', $transaction->id)->first(); if (!$precheck) { $buttons .= ''; $buttons .= 'Precheck'; $buttons .= ''; } else { // Check if postcheck exists $postcheck = \App\Models\Postcheck::where('transaction_id', $transaction->id)->first(); if (!$postcheck) { $buttons .= ''; $buttons .= 'Postcheck'; $buttons .= ''; } else { $buttons .= 'Selesai'; } } } $buttons .= 'Sudah Diklaim'; } } return $buttons; } /** * Get KPI data for AJAX refresh */ public function getKpiData() { try { $kpiService = app(\App\Services\KpiService::class); $kpiSummary = $kpiService->getKpiSummaryWithClaims(Auth::user()); $currentMonthName = now()->translatedFormat('F Y'); $kpiData = [ 'target' => $kpiSummary['current_target'] ? $kpiSummary['current_target']->target_value : 0, 'actual' => $kpiSummary['current_achievement'] ? $kpiSummary['current_achievement']->actual_value : 0, 'percentage' => $kpiSummary['current_percentage'], 'status' => $kpiSummary['current_achievement'] ? $kpiSummary['current_achievement']->status : 'pending', 'status_color' => $kpiSummary['current_achievement'] ? $kpiSummary['current_achievement']->status_color : 'secondary', 'period' => $currentMonthName, 'has_target' => $kpiSummary['current_target'] ? true : false ]; return response()->json([ 'success' => true, 'data' => $kpiData ]); } catch (Exception $e) { return response()->json([ 'success' => false, 'message' => 'Error fetching KPI data: ' . $e->getMessage() ], 500); } } }