ranjith-dev #1218

Merged
jothi merged 2 commits from ranjith-dev into master 2026-10-12 05:53:39 +00:00
4 changed files with 522 additions and 0 deletions

View File

@@ -0,0 +1,194 @@
<?php
namespace App\Filament\Pages;
use App\Models\Item;
use App\Models\ProductionPlan;
use App\Models\QualityValidation;
use App\Models\StickerMaster;
use Carbon\Carbon;
use Filament\Forms\Components\DateTimePicker;
use Filament\Pages\Page;
use Filament\Forms\Components\Section;
use Filament\Forms\Components\Select;
use Filament\Forms\Components\TextInput;
use Filament\Notifications\Notification;
use Illuminate\Support\Facades\Auth;
use Filament\Forms\Form;
use App\Models\Plant;
use Filament\Facades\Filament;
use Illuminate\Support\Facades\Log;
use Filament\Forms\Contracts\HasForms;
use Filament\Forms\Concerns\InteractsWithForms;
class ProductionNonPlannedReport extends Page implements HasForms
{
use InteractsWithForms;
protected static ?string $navigationIcon = 'heroicon-o-document-text';
protected static string $view = 'filament.pages.production-non-planned-report';
protected static ?string $navigationGroup = 'Production';
public array $filters = [];
public function mount(): void
{
$this->form->fill([
'date' => null,
'plant_id' => null,
'line_id' => null,
'category' => null,
]);
}
public function form(Form $form): Form
{
return $form
->statePath('filters')
->schema([
Section::make('')
->schema([
DateTimePicker::make('date')
->label('Choose Date')
->native(false)
->displayFormat('d-m-Y')
->reactive(),
Select::make('plant_id')
->label('Plant')
->relationship('plant', 'name')
->reactive()
// ->searchable()
->options(function (callable $get) {
$userHas = Filament::auth()->user()->plant_id;
return ($userHas && strlen($userHas) > 0) ? Plant::where('id', $userHas)->pluck('name', 'id')->toArray() : Plant::pluck('name', 'id')->toArray();
})
->required()
->afterStateUpdated(function ($state, callable $get, $set) {
// dd($state);
$set('line_id', null);
$set('category', null);
$this->dispatch('loadData',$state, '', '', '', '');
}),
Select::make('line_id')
->label('Line')
->required()
// ->relationship('line', 'name')
// ->searchable()
->columnSpan(1)
->options(function (callable $get) {
if (!$get('plant_id')) {
return [];
}
return \App\Models\Line::where('plant_id', $get('plant_id'))
->pluck('name', 'id')
->toArray();
})
->reactive()
->afterStateUpdated(function ($state, callable $get, $set) {
$plantId = $get('plant_id');
$lineId = $state;
$month = $get('month');
$year = $get('year');
$date = $get('date');
$month = (int) $get('month');
$this->dispatch('loadData',$year, $month, $plantId, $lineId, $date);
}),
// Select::make('item_id')
// ->label('Item Code')
// ->placeholder('Select Item Code')
// ->options(function (callable $get) {
// $plantId = $get('plant_id');
// $lineId = $get('line_id');
// $date = $get('date');
// if (!$plantId || !$lineId || !$date) {
// return [];
// }
// $selectedDate = Carbon::parse($date)->startOfDay();
// $startDate = $selectedDate->copy()->setTime(8, 0, 0);
// $endDate = $startDate->copy()->addDay();
// $month = $selectedDate->month;
// $year = $selectedDate->year;
// $plannedItemIds = ProductionPlan::query()
// ->where('plant_id', $plantId)
// ->where('line_id', $lineId)
// ->whereMonth('production_plans.created_at', $month)
// ->whereYear('production_plans.created_at', $year)
// ->whereNotNull('item_id')
// ->distinct()
// ->pluck('item_id');
// $stickerMasterIds = QualityValidation::query()
// ->where('plant_id', $plantId)
// ->where('line_id', $lineId)
// ->where('created_at', '>=', $startDate)
// ->where('created_at', '<', $endDate)
// ->whereNotNull('sticker_master_id')
// ->distinct()
// ->pluck('sticker_master_id');
// $producedItemIds = StickerMaster::query()
// ->whereIn('id', $stickerMasterIds)
// ->whereNotNull('item_id')
// ->distinct()
// ->pluck('item_id');
// return Item::query()
// ->whereIn('id', $producedItemIds)
// ->whereNotIn('id', $plannedItemIds)
// ->orderBy('code')
// ->pluck('code', 'id')
// ->toArray();
// })
// ->searchable()
// ->reactive()
// ->required(),
TextInput::make('category')
->label('Category')
->reactive()
->afterStateUpdated(function ($state, callable $get, $set) {
$plantId = $get('plant_id');
$lineId = $get('line_id');
// $month = $get('month');
$year = $get('year');
$month = (int) $get('month');
$category = $get('category');
}),
])
->columns(4)
]);
}
public function generateNonPlan(){
$plantId = $this->filters['plant_id'] ?? null;
$lineId = $this->filters['line_id'] ?? null;
$date = $this->filters['date'] ?? null;
$category = $this->filters['category'] ?? null;
if($category == '' || $category == null){
$this->dispatch('loadData', $date, $plantId, $lineId);
}
else{
$this->dispatch('loadDataCategory',$date, $plantId, $lineId, $category);
}
}
public static function canAccess(): bool
{
return Auth::check() && Auth::user()->can('view production non planned page');
}
}

View File

@@ -0,0 +1,278 @@
<?php
namespace App\Livewire;
use App\Models\ProductionPlan;
use App\Models\QualityValidation;
use Carbon\Carbon;
use Illuminate\Support\Facades\DB;
use Livewire\Component;
class ProductionNonPlanned extends Component
{
public $plantId, $lineId, $month, $year, $category, $date;
public $records = [];
public $nonPlannedRecords = [];
public int $nonPlannedCount = 0;
public int $nonPlannedQuantity = 0;
// public $dates = [];
public $monthlyRecords = [];
public $efficiency = [];
public $monthlyActualQuantity = [];
public $leaveDates = [];
public $dates;
public $productionPlanDates = '';
protected $listeners = [
'loadData' => 'loadProductionData',
'loadDataCategory' => 'loadProductionCategoryData'
];
public function loadProductionData($date, $plantId, $lineId)
{
$this->dates = [];
$this->leaveDates = [];
$this->nonPlannedRecords = [];
$this->nonPlannedCount = 0;
$this->nonPlannedQuantity = 0;
if (!$plantId || !$lineId || !$date) {
return;
}
$selectedDate = Carbon::parse($date);
$date = $selectedDate->toDateString();
$month = $selectedDate->month;
$year = $selectedDate->year;
$startDate = Carbon::parse($date)->setTime(8, 0, 0);
$endDate = $startDate->copy()->addDay();
$plans = ProductionPlan::query()
->join('items', 'items.id', '=', 'production_plans.item_id')
->join('lines', 'lines.id', '=', 'production_plans.line_id')
->join('plants', 'plants.id', '=', 'production_plans.plant_id')
->where('production_plans.plant_id', $plantId)
->where('production_plans.line_id', $lineId)
->whereMonth('production_plans.created_at', $month)
->whereYear('production_plans.created_at', $year)
->select(
'production_plans.item_id',
'production_plans.plant_id',
'production_plans.line_id',
'production_plans.plan_quantity',
'production_plans.working_days',
'production_plans.leave_dates',
'items.code as item_code',
'items.category as category',
'items.description as item_description',
'items.hourly_quantity as hourly_quantity',
'lines.name as line_name',
'plants.name as plant_name'
)
->get();
$plannedItemIds = $plans
->pluck('item_id')
->filter(fn ($id) => $id != null)
->unique()
->values();
$leaveDates = [];
if ($plans->isNotEmpty() && $plans->first()->leave_dates) {
$leaveDates = array_map(
'trim',
explode(',', $plans->first()->leave_dates)
);
}
$this->leaveDates = $leaveDates;
$nonPlannedQuery = QualityValidation::query()
->join(
'sticker_masters',
'sticker_masters.id',
'=',
'quality_validations.sticker_master_id'
)
->join(
'items',
'items.id',
'=',
'sticker_masters.item_id'
)
->where('quality_validations.plant_id', $plantId)
->where('quality_validations.line_id', $lineId)
->where('quality_validations.created_at', '>=', $startDate)
->where('quality_validations.created_at', '<', $endDate);
if ($plannedItemIds->isNotEmpty()) {
$nonPlannedQuery->whereNotIn(
'sticker_masters.item_id',
$plannedItemIds
);
}
$nonPlannedData = $nonPlannedQuery
->selectRaw("
sticker_masters.item_id,
items.code as item_code,
items.description as item_description,
items.category as item_category,
COUNT(*) as total_qty
")
->groupBy(
'sticker_masters.item_id',
'items.code',
'items.description',
'items.category'
)
->get();
$this->nonPlannedRecords = $nonPlannedData->toArray();
$this->nonPlannedCount = $nonPlannedData->count();
$this->nonPlannedQuantity = (int) $nonPlannedData->sum('total_qty');
}
public function loadProductionCategoryData($date, $plantId, $lineId, $category)
{
$this->dates = [];
$this->leaveDates = [];
$this->nonPlannedRecords = [];
$this->nonPlannedCount = 0;
$this->nonPlannedQuantity = 0;
if (!$plantId || !$lineId || !$date) {
return;
}
$selectedDate = Carbon::parse($date);
$date = $selectedDate->toDateString();
$month = $selectedDate->month;
$year = $selectedDate->year;
$startDate = Carbon::parse($date)->setTime(8, 0, 0);
$endDate = $startDate->copy()->addDay();
$plans = ProductionPlan::query()
->join('items', 'items.id', '=', 'production_plans.item_id')
->join('lines', 'lines.id', '=', 'production_plans.line_id')
->join('plants', 'plants.id', '=', 'production_plans.plant_id')
->where('production_plans.plant_id', $plantId)
->where('production_plans.line_id', $lineId)
->where('items.category', $category)
->whereMonth('production_plans.created_at', $month)
->whereYear('production_plans.created_at', $year)
->select(
'production_plans.item_id',
'production_plans.plant_id',
'production_plans.line_id',
'production_plans.plan_quantity',
'production_plans.working_days',
'production_plans.leave_dates',
'items.code as item_code',
'items.category as category',
'items.description as item_description',
'items.hourly_quantity as hourly_quantity',
'lines.name as line_name',
'plants.name as plant_name'
)
->get();
$plannedItemIds = $plans
->pluck('item_id')
->filter(fn ($id) => $id != null)
->unique()
->values();
$leaveDates = [];
if ($plans->isNotEmpty() && $plans->first()->leave_dates) {
$leaveDates = array_map(
'trim',
explode(',', $plans->first()->leave_dates)
);
}
$this->leaveDates = $leaveDates;
$nonPlannedQuery = QualityValidation::query()
->join(
'sticker_masters',
'sticker_masters.id',
'=',
'quality_validations.sticker_master_id'
)
->join(
'items',
'items.id',
'=',
'sticker_masters.item_id'
)
->where('quality_validations.plant_id', $plantId)
->where('quality_validations.line_id', $lineId)
->where('items.category', $category)
->where('quality_validations.created_at', '>=', $startDate)
->where('quality_validations.created_at', '<', $endDate);
if ($plannedItemIds->isNotEmpty()) {
$nonPlannedQuery->whereNotIn(
'sticker_masters.item_id',
$plannedItemIds
);
}
$nonPlannedData = $nonPlannedQuery
->selectRaw("
sticker_masters.item_id,
items.code as item_code,
items.description as item_description,
items.category as item_category,
COUNT(*) as total_qty
")
->groupBy(
'sticker_masters.item_id',
'items.code',
'items.description',
'items.category'
)
->get();
$this->nonPlannedRecords = $nonPlannedData->toArray();
$this->nonPlannedCount = $nonPlannedData->count();
$this->nonPlannedQuantity = (int) $nonPlannedData->sum('total_qty');
}
public function render()
{
// return view('livewire.production-non-planned');
return view('livewire.production-non-planned', [
'records' => $this->records,
'monthlyRecords' => $this->monthlyRecords,
'monthlyActualRecords' => $this->monthlyActualQuantity,
'monthlyEfficiency' => $this->efficiency,
'dates' => $this->dates,
]);
}
}

View File

@@ -0,0 +1,20 @@
<x-filament-panels::page>
<div class="space-y-4">
{{-- Render the Select form fields --}}
<div class="space-y-4">
{{ $this->form }}
</div>
<x-filament::button
wire:click="generateNonPlan"
color="primary"
class="mt-4"
>
Generate
</x-filament::button>
<div class="bg-white shadow rounded-xl p-4 mt-6">
<livewire:production-non-planned />
</div>
</div>
</x-filament-panels::page>

View File

@@ -0,0 +1,30 @@
<div class="p-4">
<div class="p-4 mt-6">
<h2 class="text-lg font-bold mb-4 text-gray-700 uppercase tracking-wider">
NON PLANNED PRODUCTION:
</h2>
<div class="overflow-x-auto rounded-lg shadow">
<table class="w-full divide-y divide-gray-200 text-sm text-center">
<thead class="bg-gray-100 text-sm font-semibold uppercase text-gray-700">
<tr>
<th class="border px-4 py-2">No</th>
<th class="border px-4 py-2">Item Code</th>
<th class="border px-4 py-2">Category</th>
<th class="border px-4 py-2">Non Planned Quantity</th>
</tr>
</thead>
<tbody>
@foreach ($nonPlannedRecords as $index => $item)
<tr>
<td class="border px-4 py-2">{{ $index + 1 }}</td>
<td class="border px-4 py-2">{{ $item['item_code'] }}</td>
<td class="border px-4 py-2">{{ $item['item_category'] }}</td>
<td class="border px-4 py-2">{{ $item['total_qty'] }}</td>
</tr>
@endforeach
</tbody>
</table>
</div>
</div>