diff --git a/app/Console/Commands/SendLaserStopReport.php b/app/Console/Commands/SendLaserStopReport.php
index 5407051..4dc53e5 100644
--- a/app/Console/Commands/SendLaserStopReport.php
+++ b/app/Console/Commands/SendLaserStopReport.php
@@ -2,12 +2,18 @@
namespace App\Console\Commands;
+use App\Mail\LaserStopMail;
use App\Mail\LaserStopReportMail;
+use App\Models\CharacteristicApproverMaster;
use App\Models\ClassCharacteristic;
use App\Models\Machine;
use App\Models\Plant;
+use App\Models\RequestCharacteristic;
+use App\Models\TempStopCharacteristic;
use Illuminate\Console\Command;
use Illuminate\Support\Facades\Mail;
+use Illuminate\Support\Facades\Schema;
+use Illuminate\Support\Carbon;
class SendLaserStopReport extends Command
{
@@ -16,7 +22,7 @@ class SendLaserStopReport extends Command
*
* @var string
*/
- protected $signature = 'send:laser-stop-report {schedule_type} {plant} {machine_id}';
+ protected $signature = 'approval:laser-stop';
/**
* The console command description.
@@ -25,89 +31,194 @@ class SendLaserStopReport extends Command
*/
protected $description = 'Command description';
+ public $subjectLine;
+
+ // public $tempCharacteristics = [];
+
+ public $wfId;
+
/**
* Execute the console command.
*/
public function handle()
{
- $scheduleType = $this->argument('schedule_type');
- $plantId = (int) $this->argument('plant');
- $machineId = (int) $this->argument('machine_id');
+ $this->info('Approval mail job started');
- $mailRules = \App\Models\AlertMailRule::where('module', 'LaserStopAlert')
- ->where('rule_name', 'LaserStopAlertMail')
- ->where('schedule_type', $scheduleType)
- ->where('plant', $plantId)
- ->where('machine_id', $machineId)
+ // .. Laser Stop Mail trigger logic
+
+ $stoppedRecords = 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();
- $emails = $mailRules
- ->pluck('email')
- ->filter()
- ->flatMap(function ($email) {
- return array_map('trim', explode(',', $email));
- })
- ->unique()
- ->values()
- ->toArray();
+ $stoppedRecords = $stoppedRecords->filter(function ($item) {
+ $approver = CharacteristicApproverMaster::find($item->characteristic_approver_master_id);
+ return $approver && $approver->approver_type == 'Stop';
+ });
- $ccEmails = $mailRules
- ->pluck('cc_emails')
- ->filter()
- ->flatMap(function ($email) {
- return array_map('trim', explode(',', $email));
- })
- ->unique()
- ->values()
- ->toArray();
- $plants = $plantId == 0
- ? Plant::all()
- : Plant::where('id', $plantId)->get();
-
- if ($plants->isEmpty()) {
- $this->error('No valid plant(s) found.');
+ if ($stoppedRecords->isEmpty()) {
+ $this->info('No laser stop pending approvals');
return;
}
- $plant = Plant::find($plantId);
+ $grouped = $stoppedRecords->groupBy(function ($item) {
+ $this->wfId = $item->work_flow_id;
+ return $item->plant_id . '|' . $item->machine_id . '|' . $item->aufnr . '|' . $item->work_flow_id;
+ });
- $plantName = $plant?->name ?? $plantId;
+ $pendingApprovers = RequestCharacteristic::where('work_flow_id', $this->wfId)->latest()->first();
- $machine = Machine::find($machineId);
-
- $machineName = $machine?->work_center ?? $machineId;
-
- $records = ClassCharacteristic::where('is_stopped', 2)
- ->where('plant_id', $plantId)
- ->where('machine_id', $machineId)
- ->get();
-
- if ($records->isEmpty()) {
- $this->info('No laser stop records found.');
- return;
+ $approverNameFromMaster = null;
+ if ($pendingApprovers && $pendingApprovers->characteristic_approver_master_id) {
+ $approverNameFromMaster = CharacteristicApproverMaster::find($pendingApprovers->characteristic_approver_master_id);
}
- $recordIds = $records->pluck('id');
+ $rows = [];
- // Send mail to mapped email IDs
- Mail::to($emails)
- ->cc($ccEmails)
- ->send(
- new LaserStopReportMail(
- $records,
- $plantId,
- $machineId,
- $plantName,
- $machineName,
+ 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_stop_characteristics');
+
+ $exclude = ['id', 'plant_id', 'machine_id', 'item_id', 'aufnr', 'class', 'arbid', 'gamng', 'lmnga', 'zz1_cn_bill_ord', 'created_at', 'updated_at', 'deleted_at', 'has_work_flow_id', 'created_by', 'updated_by' ];
+
+ $filteredColumns = array_diff($columns, $exclude);
+
+ $row1 = TempStopCharacteristic::where('plant_id', $first->plant_id)
+ ->where('machine_id', $first->machine_id)
+ ->where('aufnr', $first->aufnr)
+ ->where('model_type', $first->model_type)
+ ->where('gernr', $first->gernr)
+ ->latest()
+ ->first();
+
+ $stopDetails = [
+ 'samlight_logged_name' => $row1?->samlight_logged_name,
+ 'zmm_heading' => $row1?->zmm_heading,
+ 'machine_name' => $row1?->machine_name,
+ 'stopped_at' => $row1?->stopped_at,
+ 'stopped_by' => $row1?->stopped_by,
+ ];
+
+ $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;
+ }
+ }
+
+ if (!$level || !$mail) {
+ continue;
+ }
+
+ $subjectLine = 'Laser Stop Approval Mail';
+
+ $emails = array_map('trim', explode(',', $mail));
+
+ Mail::to($emails)->send(
+ new LaserStopMail(
+ $first,
+ $name,
+ $level,
+ $pendingApprovers,
+ $approverNameFromMaster,
+ $subjectLine,
+ $characteristics,
+ $stopDetails
)
);
- ClassCharacteristic::whereIn('id', $recordIds)
- ->update([
- 'is_stopped' => 1,
- ]);
+ RequestCharacteristic::whereIn('id', $groupRecords->pluck('id'))
+ ->update($updateData);
- $this->info('Laser stop report mail sent successfully.');
+ $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;
}
}
diff --git a/app/Http/Controllers/CharacteristicApprovalController.php b/app/Http/Controllers/CharacteristicApprovalController.php
index 7a5fb3e..13ada9e 100644
--- a/app/Http/Controllers/CharacteristicApprovalController.php
+++ b/app/Http/Controllers/CharacteristicApprovalController.php
@@ -424,6 +424,93 @@ class CharacteristicApprovalController extends Controller
return response()->json(['status' => true, 'message' => 'Status updated successfully']);
}
+ //..Laser Stop
+
+ public function laserApproveForm(Request $request)
+ {
+ $id = $request->query('id');
+ $level = (int) $request->query('level');
+
+ $record = RequestCharacteristic::findOrFail($id);
+
+ [$statusColumn, $approvedAtColumn, $remarkColumn] = match ($level) {
+ 1 => ['approver_status1', 'approved1_at', 'approver_remark1'],
+ 2 => ['approver_status2', 'approved2_at', 'approver_remark2'],
+ 3 => ['approver_status3', 'approved3_at', 'approver_remark3'],
+ default => abort(403, 'Invalid approver level'),
+ };
+
+ $levels = [
+ 1 => 'approver_status1',
+ 2 => 'approver_status2',
+ 3 => 'approver_status3',
+ ];
+
+ $currentStatusColumn = $levels[$level];
+
+ $currentStatus = $record->$statusColumn;
+
+ if (in_array($currentStatus, ['Approved', 'Rejected'])) {
+ return view('approval.already-processed', [
+ 'status' => $currentStatus,
+ ]);
+ }
+
+ foreach ($levels as $lvl => $column) {
+ if ($lvl != $level && in_array($record->$column, ['Approved', 'Rejected'])) {
+ return view('approval.already-processed', [
+ 'status' => $record->$column,
+ 'message' => 'Your request has already been processed by another approver',
+ ]);
+ }
+ }
+
+ // foreach ($levels as $lvl => $column) {
+ // if ($record->$column == 'Hold') {
+
+ // if ($lvl == $level) {
+ // return view('approval.reject-form', compact('id', 'level'));
+ // }
+ // else
+ // {
+ // return view('approval.already-processed', [
+ // 'status' => 'Hold',
+ // 'message' => 'On Hold',
+ // ]);
+ // }
+ // }
+ // }
+
+ $allowedMailStatusByLevel = [
+ 1 => 'Sent',
+ 2 => 'Sent-Mail2',
+ 3 => 'Sent-Mail3',
+ ];
+
+ $expectedMailStatus = $allowedMailStatusByLevel[$level] ?? null;
+
+ if ($record->mail_status != $expectedMailStatus) {
+ return view('approval.approve-level', [
+ 'status' => $currentStatus,
+ 'message' => 'Your approval time limit has expired.',
+ ]);
+ }
+
+ return view('approval.approve-form', compact('id', 'level'));
+ }
+
+
+ public function laserApproveSave(Request $request)
+ {
+ $request->validate([
+ 'id' => 'required|integer',
+ 'level' => 'required|integer',
+ 'remark' => 'nullable|string',
+ ]);
+
+ return $this->updateStatus($request, 'Approved', false);
+ }
+
public function index()
{
//
diff --git a/app/Mail/LaserStopMail.php b/app/Mail/LaserStopMail.php
index 2916470..e249d4b 100644
--- a/app/Mail/LaserStopMail.php
+++ b/app/Mail/LaserStopMail.php
@@ -8,28 +8,40 @@ use Illuminate\Mail\Mailable;
use Illuminate\Mail\Mailables\Content;
use Illuminate\Mail\Mailables\Envelope;
use Illuminate\Queue\SerializesModels;
+use Illuminate\Support\Facades\URL;
class LaserStopMail extends Mailable
{
use Queueable, SerializesModels;
- public $records;
- public $plantId;
- public $machineId;
- public $plantName;
+ public $request;
+ public $approverName;
+ public $level;
+ public $tableData;
- public $machineName;
+ public $pendingApprovers;
+
+ public $approverNameFromMaster;
+
+ public $subjectLine;
+
+ public $characteristics;
+
+ public $stopDetails;
/**
* Create a new message instance.
*/
- public function __construct($records,$plantId,$machineId, $plantName, $machineName)
+ public function __construct($request, $approverName, $level, $pendingApprovers, $approverNameFromMaster, $subjectLine, $characteristics = [], $stopDetails=[])
{
- $this->records = $records;
- $this->plantId = $plantId;
- $this->machineId = $machineId;
- $this->plantName = $plantName;
- $this->machineName = $machineName;
+ $this->request = $request;
+ $this->approverName = $approverName;
+ $this->level = $level;
+ $this->pendingApprovers = $pendingApprovers;
+ $this->approverNameFromMaster = $approverNameFromMaster;
+ $this->subjectLine = $subjectLine;
+ $this->tableData = $characteristics;
+ $this->stopDetails = $stopDetails;
}
/**
@@ -38,7 +50,7 @@ class LaserStopMail extends Mailable
public function envelope(): Envelope
{
return new Envelope(
- subject: 'Laser Marking - Consolidated Stoppage Report',
+ subject: $this->subjectLine,
);
}
@@ -47,17 +59,33 @@ class LaserStopMail extends Mailable
*/
public function content(): Content
{
- $greeting = 'Dear Sir';
return new Content(
- view: 'mail.laser-stop-final-report',
+ view: 'mail.laser-stop-report',
with: [
- 'company' => 'CRI Digital Manufacturing Solutions',
- 'greeting' => $greeting,
- 'wishes' => 'Thanks & Regards,
CRI Digital Manufacturing Solutions',
- ],
+ 'company' => 'CRI Digital Manufacturing Solutions',
+ 'greeting' => 'Dear ' . $this->approverName . ',',
+ 'request' => $this->request,
+ 'level' => $this->level,
+ 'tableData' => $this->tableData,
+ 'tempstop' => $this->stopDetails,
+ 'pendingApprovers' => $this->pendingApprovers,
+ 'approverNameFromMaster' => $this->approverNameFromMaster,
+ 'approveUrl' => $this->approveUrl(),
+ // 'holdUrl' => $this->holdUrl(),
+ // 'rejectUrl' => $this->rejectUrl(),
+ 'wishes' => 'Thanks & Regards,
CRI Digital Manufacturing Solutions',
+ ]
);
}
+ protected function approveUrl()
+ {
+ return URL::signedRoute('laser.approve', [
+ 'id' => $this->request->id,
+ 'level' => $this->level
+ ]);
+ }
+
/**
* Get the attachments for the message.
*
diff --git a/resources/views/approval/laser-approve-success.blade.php b/resources/views/approval/laser-approve-success.blade.php
new file mode 100644
index 0000000..107143a
--- /dev/null
+++ b/resources/views/approval/laser-approve-success.blade.php
@@ -0,0 +1,77 @@
+
+
+
Your request has been approved.
+ + + +{!! $greeting !!}
-| - - - - + | Title | +Details | +
|---|---|---|
| Stopped Date Time | + {{--{{ $tempstop['stopped_at']->format('d-m-Y H:i:s') }} | --}} ++ {{ $tempstop['stopped_at'] + ? \Carbon\Carbon::parse($tempstop['stopped_at'])->format('d-m-Y H:i:s') + : '' }} |
| Plant Name | +{{ $request->plant->name ?? $request->plant_id }} | +|
| Work Center | +{{ $request->machine->work_center ?? $request->machine_id }} | +|
| Machine Name | +{{ $tempstop['machine_name'] }} | +|
| Item Code | +{{ $request->item->code ?? $request->code }} | +|
| Description | +{{ $request->item->description ?? $request->description }} | +|
| Job Number | +{{ $request->aufnr }} | +|
| Serial Number | +{{ $request->gernr }} | +|
| ZMM Heading | +{{ $tempstop['zmm_heading'] }} | +|
| Model Type | +{{ $request->model_type }} | +|
| SL Logged Name | +{{ $tempstop['samlight_logged_name'] }} | +|
| Work Flow ID | +{{ $request->work_flow_id }} | +|
| Stopped By | +{{ $tempstop['stopped_by'] }} | +
| Approver Name | +Approve Status | +
|---|---|
| {{ $approverNameFromMaster->name1 }} | +{{ ucfirst($pendingApprovers->approver_status1 ?? '-') }} | +
| {{ $approverName }} | ++ Approve + {{-- | + Hold + | + Reject --}} + | +
| {{ $approverNameFromMaster->name1 }} | +{{ ucfirst($pendingApprovers->approver_status1 ?? '-') }} | +
| {{ $approverNameFromMaster->name2 }} | +{{ ucfirst($pendingApprovers->approver_status2 ?? '-') }} | +
| {{ $approverName }} | ++ Approve + | + {{-- Hold + | --}} + {{-- Reject --}} + | +
| {{ $approverName }} | ++ Approve + {{-- | + Hold + | + Reject --}} + | +
{!! $wishes !!}
+ diff --git a/routes/web.php b/routes/web.php index e33905e..9ab9f7b 100644 --- a/routes/web.php +++ b/routes/web.php @@ -17,42 +17,6 @@ Route::get('/', function () { return redirect('/admin'); }); -// Route::get('/admin', function () { -// return redirect('/admin/welcome'); -// }); - -// Route::get('/password-reset/approve/{token}', function ($token) { - -// // $workerId = cache()->pull("password-reset-approval-{$token}"); - -// $workerId = cache()->get("password-reset-approval-{$token}"); - -// if (! $workerId) { -// return response()->view('errors.password-reset-expired', [], 410); -// } - -// $worker = User::findOrFail($workerId); - - -// $resetToken = Password::broker()->createToken($worker); - - -// $resetUrl = URL::temporarySignedRoute( -// 'filament.admin.auth.password-reset.reset', -// Carbon::now()->addMinutes(60), -// [ -// 'email' => $worker->email, -// 'token' => $resetToken, -// ] -// ); - - -// return redirect()->to($resetUrl); - -// })->middleware('signed')->name('password-reset.approve'); - -//.. - Route::get('/sticker/preview/{path}', function ($path) { $file = storage_path('app/' . $path); @@ -101,6 +65,21 @@ Route::get('/approval/approve-success', function () { return view('approval.approve-success'); })->name('approval.approve.success'); +//..Laser Stop Approval + +Route::get('/laser/stop/approve', [CharacteristicApprovalController::class, 'laserApproveForm']) + ->name('laser.approve') + ->middleware('signed'); + +Route::post('/laser/approve-save', [CharacteristicApprovalController::class, 'laserApproveSave']) + ->name('laser.approve.save'); + +Route::get('/laser/stop/approval/approve-success', function () { + return view('approval.laser-approve-success'); +})->name('approval.laser.approve.success'); + +//.. + Route::get('/production-orders/print/{production_order}', [ProductionOrderController::class, 'print'] )->name('production-orders.print');