info('Approval mail job started'); // .. Characteristic Mail trigger logic // $records = RequestCharacteristic::whereNull('approver_status1') // ->whereNull('approver_status2') // ->whereNull('approver_status3') // ->get(); $records = RequestCharacteristic::where(function ($q) { $q->whereNull('approver_status1') ->orWhere('approver_status1', 'Hold'); }) ->where(function ($q) { $q->whereNull('approver_status2') ->orWhere('approver_status2', 'Hold'); }) ->where(function ($q) { $q->whereNull('approver_status3') ->orWhere('approver_status3', 'Hold'); }) ->get(); $records = $records->filter(function ($item) { $approver = CharacteristicApproverMaster::find($item->characteristic_approver_master_id); return $approver && $approver->approver_type == 'Characteristic'; }); if ($records->isEmpty()) { $this->info('No characteristics pending approvals'); }else{ $grouped = $records->groupBy(function ($item) { $this->wfId = $item->work_flow_id; return $item->plant_id . '|' . $item->machine_id . '|' . $item->aufnr . '|' . $item->work_flow_id; }); $pendingApprovers = RequestCharacteristic::where('work_flow_id', $this->wfId)->latest()->first(); $this->info($pendingApprovers->approver_status1, $pendingApprovers->approver_status2); $approverNameFromMaster = null; if ($pendingApprovers && $pendingApprovers->characteristic_approver_master_id) { $approverNameFromMaster = CharacteristicApproverMaster::find($pendingApprovers->characteristic_approver_master_id); } $rows = []; foreach ($grouped as $groupRecords) { $first = $groupRecords->first(); $approver = CharacteristicApproverMaster::where('plant_id', $first->plant_id) ->where('machine_id', $first->machine_id) ->where('id', $first->characteristic_approver_master_id) ->first(); if (!$approver) { continue; } $characteristics = $groupRecords->map(fn ($r) => [ 'work_flow_id' => $r->work_flow_id, 'characteristic_name' => $r->characteristic_name, 'current_value' => $r->current_value, 'update_value' => $r->update_value, ])->toArray(); $level = null; $mail = null; $name = null; $updateData = []; $now = Carbon::now(); // --- FIRST MAIL --- if (is_null($first->mail_status)){ $level = 1; $mail = $approver->mail1; $name = $approver->name1; $updateData['mail_status'] = 'Sent'; if ($approver->duration1 > 0) { $duration = number_format((float)$approver->duration1, 2, '.', ''); [$hours, $minutes] = explode('.', $duration); $totalMinutes = ((int)$hours * 60) + (int)$minutes; $updateData['trigger_at'] = $now ->copy() ->addMinutes($totalMinutes) ->startOfMinute(); } else { $updateData['trigger_at'] = null; } } // --- SECOND MAIL --- elseif ( $first->mail_status == 'Sent' && (is_null($first->approver_status1) || $first->approver_status1 == 'Hold') && $first->trigger_at && \Carbon\Carbon::parse($first->trigger_at)->lte($now) ) { $this->info( "mail_status: {$first->mail_status}, ". "approver_status1: {$first->approver_status1}, ". "trigger_at: {$first->trigger_at}, ". "now: {$now}" ); $level = 2; $mail = $approver->mail2; $name = $approver->name2; if ($approver->duration2 > 0) { $duration = number_format((float)$approver->duration2, 2, '.', ''); [$hours, $minutes] = explode('.', $duration); $totalMinutes = ((int)$hours * 60) + (int)$minutes; $updateData['trigger_at'] = $now->copy()->addMinutes($totalMinutes); } else { $updateData['trigger_at'] = null; } $updateData['mail_status'] = 'Sent-Mail2'; } // --- THIRD MAIL --- elseif ( $first->mail_status == 'Sent-Mail2' && (is_null($first->approver_status1) || $first->approver_status1 == 'Hold') && (is_null($first->approver_status2) || $first->approver_status2 == 'Hold') && $first->trigger_at && \Carbon\Carbon::parse($first->trigger_at)->lte($now) ) { $level = 3; $mail = $approver->mail3; $name = $approver->name3; $updateData['trigger_at'] = null; $updateData['mail_status'] = 'Sent-Mail3'; } $totalMinutes = $this->convertToMinutes($approver->duration1 ?? 0) + $this->convertToMinutes($approver->duration2 ?? 0) + $this->convertToMinutes($approver->duration3 ?? 0); $expiryTime = Carbon::parse($first->created_at) ->copy() ->addMinutes($totalMinutes); $ids = $groupRecords->pluck('id'); $this->info("Expiry Time for ID {$first->id}: {$expiryTime}, Now: {$now}"); // --- AUTO REJECT --- if ( $first->mail_status == 'Sent-Mail3' && (is_null($first->approver_status1) || $first->approver_status1 == 'Hold') && (is_null($first->approver_status2) || $first->approver_status2 == 'Hold') && (is_null($first->approver_status3) || $first->approver_status3 == 'Hold') && $now->gte($expiryTime) ) { RequestCharacteristic::whereIn('id', $ids) ->update([ 'approver_status3' => 'Rejected', 'approver_remark3' => 'Time Limit Reached', 'approved3_at' => now(), ]); $this->info("Auto Rejected ID: {$first->id}"); continue; } if (!$level || !$mail) { continue; } $pdfPath = 'uploads/LaserDocs/' . $first->work_flow_id . '.pdf'; $subjectLine = 'Characteristic Approval Mail'; // $emails = array_map('trim', explode(',', $mail)); Mail::to($mail)->send( new CharacteristicApprovalMail( $first, $name, $level, $pdfPath, $pendingApprovers, $approverNameFromMaster, $subjectLine, $characteristics ) ); RequestCharacteristic::whereIn('id', $groupRecords->pluck('id')) ->update($updateData); $rows[] = [ $first->id, $first->plant_id, $first->machine_id, "Level $level", $mail, 'SENT' ]; } } // .. Quality Mail trigger logic $qualityRecords = RequestCharacteristic::where(function ($q) { $q->whereNull('approver_status1') ->orWhere('approver_status1', 'Hold'); }) ->where(function ($q) { $q->whereNull('approver_status2') ->orWhere('approver_status2', 'Hold'); }) ->where(function ($q) { $q->whereNull('approver_status3') ->orWhere('approver_status3', 'Hold'); }) ->get(); $qualityRecords = $qualityRecords->filter(function ($item) { $approver = CharacteristicApproverMaster::find($item->characteristic_approver_master_id); return $approver && $approver->approver_type == 'Quality'; }); // $approvers = CharacteristicApproverMaster::where('approver_type', 'Quality') // ->get() // ->keyBy('id'); // $qualityRecords = RequestCharacteristic::where(function ($q) { // $q->whereNull('approver_status1')->orWhere('approver_status1', 'Hold'); // }) // ->where(function ($q) { // $q->whereNull('approver_status2')->orWhere('approver_status2', 'Hold'); // }) // ->where(function ($q) { // $q->whereNull('approver_status3')->orWhere('approver_status3', 'Hold'); // }) // ->whereIn('characteristic_approver_master_id', $approvers->keys()) // ->get(); if ($qualityRecords->isEmpty()) { $this->info('No quality pending approvals'); return; } $grouped = $qualityRecords->groupBy(function ($item) { $this->wfId = $item->work_flow_id; return $item->plant_id . '|' . $item->machine_id . '|' . $item->aufnr . '|' . $item->work_flow_id; }); $pendingApprovers = RequestCharacteristic::where('work_flow_id', $this->wfId)->latest()->first(); $approverNameFromMaster = null; if ($pendingApprovers && $pendingApprovers->characteristic_approver_master_id) { $approverNameFromMaster = CharacteristicApproverMaster::find($pendingApprovers->characteristic_approver_master_id); } $rows = []; foreach ($grouped as $groupRecords) { $first = $groupRecords->first(); $approver = CharacteristicApproverMaster::where('plant_id', $first->plant_id) ->where('machine_id', $first->machine_id) ->where('id', $first->characteristic_approver_master_id) ->first(); if (!$approver) { continue; } $columns = Schema::getColumnListing('temp_class_characteristics'); $exclude = ['id', 'plant_id', 'machine_id', 'item_id', 'aufnr', 'class', 'arbid', 'gamng', 'lmnga', 'zz1_cn_bill_ord', 'zmm_heading', 'created_at', 'updated_at', 'deleted_at', 'has_work_flow_id', 'model_type', 'created_by', 'updated_by' ]; $filteredColumns = array_diff($columns, $exclude); $row1 = TempClassCharacteristic::where('plant_id', $first->plant_id) ->where('machine_id', $first->machine_id) ->where('aufnr', $first->aufnr) ->where('model_type', $first->model_type) ->latest() ->first(); $this->info(json_encode([ 'id' => $row1->id, 'plant_id' => $row1->plant_id, 'machine_id' => $row1->machine_id, 'aufnr' => $row1->aufnr, 'motor_speed' => $row1->zmm_motor_speed, 'all_data' => $row1->toArray(), ])); $data = []; if ($row1) { foreach ($filteredColumns as $column) { $value = $row1->getAttribute($column); if ($value != null && $value != '') { $data[$column] = $value; } } } $characteristics = $data; $level = null; $mail = null; $name = null; $updateData = []; $now = Carbon::now(); // --- FIRST MAIL --- if (is_null($first->mail_status)){ $level = 1; $mail = $approver->mail1; $name = $approver->name1; $updateData['mail_status'] = 'Sent'; if ($approver->duration1 > 0) { $duration = number_format((float)$approver->duration1, 2, '.', ''); [$hours, $minutes] = explode('.', $duration); $totalMinutes = ((int)$hours * 60) + (int)$minutes; $updateData['trigger_at'] = $now ->copy() ->addMinutes($totalMinutes) ->startOfMinute(); } else { $updateData['trigger_at'] = null; } } // --- SECOND MAIL --- elseif ( $first->mail_status == 'Sent' && (is_null($first->approver_status1) || $first->approver_status1 == 'Hold') && $first->trigger_at && \Carbon\Carbon::parse($first->trigger_at)->lte($now) ) { $level = 2; $mail = $approver->mail2; $name = $approver->name2; if ($approver->duration2 > 0) { $duration = number_format((float)$approver->duration2, 2, '.', ''); [$hours, $minutes] = explode('.', $duration); $totalMinutes = ((int)$hours * 60) + (int)$minutes; // IMPORTANT: use NOW, not old trigger $updateData['trigger_at'] = $now->copy()->addMinutes($totalMinutes); } else { $updateData['trigger_at'] = null; } $updateData['mail_status'] = 'Sent-Mail2'; } // --- THIRD MAIL --- elseif ( $first->mail_status == 'Sent-Mail2' && (is_null($first->approver_status1) || $first->approver_status1 == 'Hold') && (is_null($first->approver_status2) || $first->approver_status2 == 'Hold') && $first->trigger_at && \Carbon\Carbon::parse($first->trigger_at)->lte($now) ) { $level = 3; $mail = $approver->mail3; $name = $approver->name3; $updateData['trigger_at'] = null; $updateData['mail_status'] = 'Sent-Mail3'; } $totalMinutes = $this->convertToMinutes($approver->duration1 ?? 0) + $this->convertToMinutes($approver->duration2 ?? 0) + $this->convertToMinutes($approver->duration3 ?? 0); $expiryTime = Carbon::parse($first->created_at) ->copy() ->addMinutes($totalMinutes); $ids = $groupRecords->pluck('id'); $this->info("Expiry Time for ID {$first->id}: {$expiryTime}, Now: {$now}"); // --- AUTO REJECT --- if ( $first->mail_status == 'Sent-Mail3' && (is_null($first->approver_status1) || $first->approver_status1 == 'Hold') && (is_null($first->approver_status2) || $first->approver_status2 == 'Hold') && (is_null($first->approver_status3) || $first->approver_status3 == 'Hold') && $now->gte($expiryTime) ) { RequestCharacteristic::whereIn('id', $ids) ->update([ 'approver_status3' => 'Rejected', 'approver_remark3' => 'Time Limit Reached', 'approved3_at' => now(), ]); $this->info("Auto Rejected ID: {$first->id}"); continue; } if (!$level || !$mail) { continue; } $pdfPath = ($f = glob(storage_path('app/private/uploads/LaserDocs/' . $first->work_flow_id . '.*'))) ? 'uploads/LaserDocs/' . basename($f[0]) : null; $this->info( $pdfPath); $subjectLine = 'Quality Approval Mail'; $emails = array_map('trim', explode(',', $mail)); Mail::to($emails)->send( new CharacteristicApprovalMail( $first, $name, $level, $pdfPath, $pendingApprovers, $approverNameFromMaster, $subjectLine, $characteristics ) ); RequestCharacteristic::whereIn('id', $groupRecords->pluck('id')) ->update($updateData); $rows[] = [ $first->id, $first->plant_id, $first->machine_id, "Level $level", $mail, 'SENT' ]; } $this->table( ['ID', 'Plant', 'Machine', 'Level', 'Mail', 'Status'], $rows ); $this->info('Approval mail job completed'); } public function convertToMinutes($duration) { if (!$duration) return 0; $parts = explode('.', (string)$duration); $hours = (int)($parts[0] ?? 0); $minutes = (int)($parts[1] ?? 0); return ($hours * 60) + $minutes; } }