ranjith-dev #1236

Merged
jothi merged 2 commits from ranjith-dev into master 2026-10-13 09:04:05 +00:00
3 changed files with 364 additions and 0 deletions

View File

@@ -0,0 +1,212 @@
<?php
namespace App\Console\Commands;
use App\Mail\NonPlanProductionMail;
use App\Models\Line;
use App\Models\Plant;
use App\Models\ProductionPlan;
use App\Models\ProductionQuantity;
use Illuminate\Console\Command;
class SendNonPlannedProductionReport extends Command
{
/**
* The name and signature of the console command.
*
* @var string
*/
protected $signature = 'send:non-planned-production-report {schedule_type} {plant}';
/**
* The console command description.
*
* @var string
*/
protected $description = 'Command description';
/**
* Execute the console command.
*/
public function handle()
{
$scheduleType = $this->argument('schedule_type');
$plantId = (int) $this->argument('plant');
$mailRules = \App\Models\AlertMailRule::where('module', 'ProductionNonPlanQuantities')
->where('rule_name', 'NonPlanProductionMail')
->where('schedule_type', $scheduleType)
->where('plant', $plantId)
->get();
$emails = $mailRules->pluck('email')->unique()->toArray();
$plants = $plantId == 0
? Plant::all()
: Plant::where('id', $plantId)->get();
if ($plants->isEmpty()) {
$this->error('No valid plant(s) found.');
return;
}
if (strtolower($scheduleType) == 'daily') {
$startDate = now()->subDay()->setTime(8, 0, 0);
$endDate = now()->setTime(8, 0, 0);
}
else {
$startDate = now()->setTime(8, 0, 0);
$endDate = now()->copy()->addDay()->setTime(8, 0, 0);
}
$tableData = [];
$no = 1;
foreach ($plants as $plant) {
$lines = Line::where('plant_id', $plant->id)
->whereIn('type', [
'Base FG Line',
'FG Line',
'Process FG Line',
'SFG Line',
])
->orderByRaw("
CASE
WHEN LOWER(type) = 'fg line' THEN 0
WHEN LOWER(type) = 'base fg line' THEN 1
WHEN LOWER(type) = 'process fg line' THEN 2
WHEN LOWER(type) = 'sfg line' THEN 3
ELSE 4
END
")
->get();
$month = $startDate->month;
$year = $startDate->year;
foreach ($lines as $line) {
$dayproductionQuantity = 0;
$nightproductionQuantity = 0;
$nonPlannedproductionQuantity = 0;
$totalActualProduction = 0;
$itemIds = ProductionPlan::where('plant_id', $plant->id)
->where('line_id', $line->id)
->whereMonth('created_at', $month)
->whereYear('created_at', $year)
->distinct()
->pluck('item_id');
if (strtolower($line->type) == 'fg line') {
$actualTotalQuantity = \App\Models\QualityValidation::where('plant_id', $plant->id)
->where('line_id', $line->id)
->whereBetween('created_at', [$startDate, $endDate])
->count();
$totalActualProduction = $actualTotalQuantity;
$nonPlannedproductionQuantity = \App\Models\QualityValidation::where('plant_id', $plant->id)
->where('line_id', $line->id)
->whereHas('stickerMaster', function ($query) use ($itemIds) {
$query->whereNotIn('item_id', $itemIds);
})
->whereBetween('created_at', [$startDate, $endDate])
->count();
$nonPlannedPercentage = $totalActualProduction > 0
? round(($nonPlannedproductionQuantity / $totalActualProduction) * 100, 2)
: 0;
}
else {
$nonPlannedproductionQuantity = ProductionQuantity::where('plant_id', $plant->id)
->where('line_id', $line->id)
->whereBetween('created_at', [$startDate, $endDate])
->count();
}
if (strtolower($line->type) == 'fg line') {
$dayproductionQuantity = \App\Models\QualityValidation::where('plant_id', $plant->id)
->where('line_id', $line->id)
->whereHas('stickerMaster', function ($query) use ($itemIds) {
$query->whereNotIn('item_id', $itemIds);
})
->whereBetween('created_at', [
$startDate->copy()->setTime(8, 0, 0),
$startDate->copy()->setTime(19, 30, 0),
])
->count();
$nightproductionQuantity = \App\Models\QualityValidation::where('plant_id', $plant->id)
->where('line_id', $line->id)
->whereHas('stickerMaster', function ($query) use ($itemIds) {
$query->whereNotIn('item_id', $itemIds);
})
->whereBetween('created_at', [
$startDate->copy()->setTime(19, 30, 0),
$endDate->copy()->setTime(8, 0, 0),
])
->count();
}
$tableData[] = [
'no' => $no++,
'plant' => $plant->name,
'type' => $line->type,
'line' => $line->name,
'dayShiftActualQuantity' => floor($dayproductionQuantity),
'nightShiftActualQuantity' => floor($nightproductionQuantity),
'uom' => $line->uom,
'totalActualQuantity' => $totalActualProduction,
'nonPlannedQuantity' => $nonPlannedproductionQuantity,
'nonPlannedPercentage' => $nonPlannedPercentage,
];
}
}
$mail = new NonPlanProductionMail($scheduleType, $tableData);
$contentVars = $mail->content()->with;
$this->info($contentVars['greeting'] ?? 'Production Report');
$this->table(
['No', 'Plant', 'Line', 'Type', 'Target Quantity', 'Production Quantity'],
$tableData
);
$this->info($contentVars['wishes'] ?? '');
foreach ($mailRules as $rule)
{
$toEmails = collect(explode(',', $rule->email))
->map(fn ($e) => trim($e))
->filter()
->unique()
->values()
->toArray();
$ccEmails = collect(explode(',', $rule->cc_emails))
->map(fn ($e) => trim($e))
->filter()
->unique()
->values()
->toArray();
if (empty($toEmails)) {
$this->warn("Skipping rule ID {$rule->id} — no valid To emails found.");
continue;
}
\Mail::to($toEmails)->cc($ccEmails)->send($mail);
$this->info("Mail sent for rule ID {$rule->id} → To: ".implode(', ', $toEmails).($ccEmails ? ' | CC: '.implode(', ', $ccEmails) : ''));
}
}
}

View File

@@ -0,0 +1,89 @@
<?php
namespace App\Mail;
use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Mail\Mailable;
use Illuminate\Mail\Mailables\Content;
use Illuminate\Mail\Mailables\Envelope;
use Illuminate\Queue\SerializesModels;
use DateTime;
class NonPlanProductionMail extends Mailable
{
use Queueable, SerializesModels;
public $tableData;
public $scheduleType;
/**
* Create a new message instance.
*/
public function __construct($scheduleType, $tableData = [])
{
$this->scheduleType = $scheduleType;
$this->tableData = $tableData ?? [];
}
/**
* Get the message envelope.
*/
public function envelope(): Envelope
{
return new Envelope(
subject: 'Non Planned Production Report',
);
}
/**
* Get the message content definition.
*/
public function content(): Content
{
$greeting = "Dear Sir/Madam,<br><br>Kindly find the attached non planned production report status details 'Production Quantity' count,";
if ($this->scheduleType == 'Daily') {
$fromDate = (new DateTime('yesterday 08:00'))->format('d/m/Y H:i').':000';
$toDate = (new DateTime('today 07:59'))->format('d/m/Y H:i').':999';
$reportPeriod = "The following report presents results from: $fromDate to $toDate.";
$greeting .= $reportPeriod;
}
if ($this->scheduleType == 'Hourly') {
$now = now();
$fromHour = $now->copy()->subHour()->format('H:i:s');
$toHour = $now->format('H:i:s');
$reportDate = $now->format('d/m/Y');
$greeting .= "The following report presents results from: $reportDate, $fromHour to $toHour.";
}
if ($this->scheduleType == 'Live') {
$now = now();
$fromMinute = $now->copy()->subMinute()->format('d/m/Y H:i:s');
$toMinute = $now->format('d/m/Y H:i:s');
$greeting .= "The following report presents results from: $fromMinute to $toMinute.";
}
return new Content(
view: 'mail.non_plan_production_report',
with: [
'company' => 'CRI Digital Manufacturing Solutions',
'greeting' => $greeting,
'tableData' => $this->tableData,
'wishes' => 'Thanks & Regards,<br>CRI Digital Manufacturing Solutions',
],
);
}
/**
* Get the attachments for the message.
*
* @return array<int, \Illuminate\Mail\Mailables\Attachment>
*/
public function attachments(): array
{
return [];
}
}

View File

@@ -0,0 +1,63 @@
<!DOCTYPE html>
<html>
<head>
<title>Non Plan Production Table</title>
<style>
table {
border-collapse: collapse;
width: 60%;
}
th, td {
border: 1px solid #444;
padding: 8px;
text-align: left;
}
th {
background: #f2f2f2;
}
</style>
</head>
<body>
<div style="text-align: center; font-weight: bold;">
{{ $company }}
</div>
<br>
<p>{!! $greeting !!}</p>
<table>
<thead>
<tr>
<th style="text-align: center; border: 1px solid #444; padding: 8px; background: #f2f2f2;">No</th>
<th style="text-align: center; border: 1px solid #444; padding: 8px; background: #f2f2f2;">Plant</th>
<th style="text-align: center; border: 1px solid #444; padding: 8px; background: #f2f2f2;">Line</th>
<th style="text-align: center; border: 1px solid #444; padding: 8px; background: #f2f2f2;">Line Type</th>
<th style="text-align: center; border: 1px solid #444; padding: 8px; background: #f2f2f2;">Day Shift Non Plan Production</th>
<th style="text-align: center; border: 1px solid #444; padding: 8px; background: #f2f2f2;">Night Shift Non Plan Production</th>
{{-- <th style="text-align: center; border: 1px solid #444; padding: 8px; background: #f2f2f2;">Actual Production</th> --}}
<th style="text-align: center; border: 1px solid #444; padding: 8px; background: #f2f2f2;">Actual Non Plan Production</th>
<th style="text-align: center; border: 1px solid #444; padding: 8px; background: #f2f2f2;">
Non Plan Production %
</th>
</tr>
</thead>
<tbody>
@foreach($tableData as $row)
<tr>
<td style="border: 1px solid #444; padding: 8px; text-align: center;">{{ $row['no'] }}</td>
<td style="border: 1px solid #444; padding: 8px; text-align: center; white-space: nowrap;">{{ $row['plant'] }}</td>
<td style="border: 1px solid #444; padding: 8px; text-align: center; white-space: nowrap;">{{ $row['line'] }}</td>
<td style="border: 1px solid #444; padding: 8px; text-align: center; white-space: nowrap;">{{ $row['type'] }}</td>
<td style="border: 1px solid #444; padding: 8px; text-align: center;">{{ $row['dayShiftActualQuantity'] }}</td>
<td style="border: 1px solid #444; padding: 8px; text-align: center;">{{ $row['nightShiftActualQuantity'] }}</td>
{{-- <td style="border: 1px solid #444; padding: 8px; text-align: center;">{{ $row['totalActualQuantity'] }}</td> --}}
<td style="border: 1px solid #444; padding: 8px; text-align: center;">{{ $row['nonPlannedQuantity'] }}</td>
<td style="border: 1px solid #444; padding: 8px; text-align: center;">
{{ $row['nonPlannedPercentage'] }}%
</td>
</tr>
@endforeach
</tbody>
</table>
<p>{!! $wishes !!}</p>
</body>
</html>