Files
CKB/app/Http/Controllers/TransactionController.php

1291 lines
53 KiB
PHP
Executable File

<?php
namespace App\Http\Controllers;
use App\Models\Category;
use App\Models\Dealer;
use App\Models\Product;
use App\Models\Stock;
use App\Models\Transaction;
use App\Models\User;
use App\Models\Work;
use App\Services\StockService;
use Illuminate\Http\Request;
use Illuminate\Support\Carbon;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Validator;
use Exception;
class TransactionController extends Controller
{
protected $stockService;
public function __construct(StockService $stockService)
{
$this->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')
->where('users.dealer_id', Auth::user()->dealer_id);
$transaction_works = Work::select('id', 'name', 'shortname')->whereHas('transactions', function($q) {
return $q->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')
->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();
foreach($transaction_sas as $sa) {
$tm1[$work['shortname']]['data'][] = $sa['sa_name'].":".$sa['qty'];
}
$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();
$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();
return view('transaction.lists', compact('transaction_dealers', 'transaction_mechanics', 'mechanic', 'sas', 'dealers', 'works', 'date_start', 'date_end'));
}
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')->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->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->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'))->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::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::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::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->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->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'))->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::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::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')->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')->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::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')
];
$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'
])
->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 '<span class="badge badge-warning">Menunggu</span>';
case 1: // completed
return '<span class="badge badge-success">Closed</span>';
default:
return '<span class="badge badge-secondary">Tidak Diketahui</span>';
}
}
/**
* 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::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);
}
// Check if transaction was created by SA (role_id = 4)
$creator = User::find($transaction->user_id);
if (!$creator || $creator->role_id != 4) {
return response()->json([
'status' => 400,
'message' => 'Hanya transaksi yang dibuat oleh Service Advisor yang dapat diklaim'
], 400);
}
// Update transaction with claim information
$transaction->update([
'claimed_at' => now(),
'claimed_by' => Auth::user()->id
]);
// Recalculate KPI achievement after claiming
$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 .= '<button class="btn btn-sm btn-success mr-1" onclick="claimTransaction(' . $transaction->id . ')" title="Klaim Pekerjaan">';
$buttons .= 'Klaim';
$buttons .= '</button>';
} 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 .= '<a href="/transaction/prechecks/' . $transaction->id . '" class="btn btn-sm btn-warning mr-1" title="Precheck">';
$buttons .= 'Precheck';
$buttons .= '</a>';
} else {
// Check if postcheck exists
$postcheck = \App\Models\Postcheck::where('transaction_id', $transaction->id)->first();
if (!$postcheck) {
$buttons .= '<a href="/transaction/postchecks/' . $transaction->id . '" class="btn btn-sm btn-info mr-1" title="Postcheck">';
$buttons .= 'Postcheck';
$buttons .= '</a>';
} else {
$buttons .= '<span class="badge badge-success">Selesai</span>';
}
}
}
$buttons .= '<span class="badge badge-info">Sudah Diklaim</span>';
}
}
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);
}
}
}