Initial commit for new repo
All checks were successful
Scan for leaked secrets using Kingfisher / kingfisher-secrets-scan (push) Successful in 1m4s

This commit is contained in:
dhanabalan
2025-12-16 17:05:04 +05:30
commit 3f0d529640
862 changed files with 141157 additions and 0 deletions

View File

@@ -0,0 +1,218 @@
<?php
namespace App\Filament\Resources;
use App\Filament\Resources\AlertMailRuleResource\Pages;
use App\Filament\Resources\AlertMailRuleResource\RelationManagers;
use App\Models\AlertMailRule;
use App\Models\Plant;
use Dotenv\Exception\ValidationException;
use Filament\Facades\Filament;
use Filament\Forms;
use Filament\Forms\Components\Checkbox;
use Filament\Forms\Form;
use Filament\Resources\Resource;
use Filament\Tables;
use Filament\Tables\Table;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Database\Eloquent\SoftDeletingScope;
use Filament\Forms\Components\Section;
use Illuminate\Validation\ValidationException as ValidationValidationException;
class AlertMailRuleResource extends Resource
{
protected static ?string $model = AlertMailRule::class;
protected static ?string $navigationIcon = 'heroicon-o-rectangle-stack';
protected static ?string $navigationGroup = 'Alert Mail';
public static function form(Form $form): Form
{
return $form
->schema([
Section::make('')
->schema([
Forms\Components\Select::make('plant')
->label('Plant')
->reactive()
->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(fn ($get) => ! $get('is_active'))
->afterStateUpdated(fn ($state, callable $set) => $state ? $set('is_active', false) : null),
// ->options(fn () => Plant::pluck('id', 'name')->toArray()),
Forms\Components\Select::make('module')
->label('Module')
->required()
->options([
'InvoiceValidation' => 'InvoiceValidation',
'InvoiceDataReport' => 'InvoiceDataReport',
'ProductionQuantities' => 'ProductionQuantities',
'QualityValidation' => 'QualityValidation',
]),
Forms\Components\Select::make('rule_name')
->label('Rule Name')
->options([
'InvoiceMail' => 'Invoice Mail',
'SerialInvoiceMail' => 'Serial Invoice Mail',
'MaterialInvoiceMail' => 'Material Invoice Mail',
'ProductionMail' => 'Production Mail',
'InvoiceDataMail' => 'Invoice Data Mail',
'QualityMail' => 'Quality Mail',
])
->required(),
Forms\Components\TextInput::make('email')
->label('Email')
->required(),
Forms\Components\Textarea::make('cc_emails')
->label('CC Emails'),
Forms\Components\Select::make('schedule_type')
->label('Schedule Type')
->options([
'Live' => 'Live',
'Hourly' => 'Hourly',
'Daily' => 'Daily',
]),
Checkbox::make('is_active')
->label('All Plants Reports')
->afterStateUpdated(fn ($state, callable $set) => $state ? $set('plant', null) : null)
->reactive(),
Forms\Components\Hidden::make('created_by')
->default(fn () => Filament::auth()->user()?->name),
Forms\Components\Hidden::make('updated_by')
->default(fn () => Filament::auth()->user()?->name),
])
->columns(6),
]);
}
// Optionally, also override for update/editing
// public static function mutateFormDataBeforeSave(array $data): array
// {
// dd('test');
// if ($data['is_active']) {
// $data['plant'] = 'All Plants';
// }
// return $data;
// }
public static function table(Table $table): Table
{
return $table
->columns([
Tables\Columns\TextColumn::make('No.')
->label('No.')
->getStateUsing(function ($record, $livewire, $column, $rowLoop) {
$paginator = $livewire->getTableRecords();
$perPage = method_exists($paginator, 'perPage') ? $paginator->perPage() : 10;
$currentPage = method_exists($paginator, 'currentPage') ? $paginator->currentPage() : 1;
return ($currentPage - 1) * $perPage + $rowLoop->iteration;
}),
Tables\Columns\TextColumn::make('plant')
->label('Plant Name')
->alignCenter()
->searchable()
->sortable()
->formatStateUsing(function ($state) {
static $plants;
if (! $plants) {
$plants = Plant::pluck('name', 'id')->toArray();
}
return $plants[$state] ?? 'All Plants';
}),
Tables\Columns\TextColumn::make('module')
->label('Module Name')
->alignCenter()
->searchable()
->sortable(),
Tables\Columns\TextColumn::make('rule_name')
->label('Rule Name')
->alignCenter()
->searchable()
->sortable(),
Tables\Columns\TextColumn::make('email')
->label('TO Emails')
->searchable()
->alignCenter()
->sortable(),
Tables\Columns\TextColumn::make('cc_emails')
->label('CC Emails')
->searchable()
->alignCenter()
->sortable(),
Tables\Columns\TextColumn::make('schedule_type')
->label('Schedule Type')
->searchable()
->alignCenter()
->sortable(),
Tables\Columns\TextColumn::make('created_at')
->label('Created At')
->alignCenter()
->dateTime()
->sortable()
->toggleable(isToggledHiddenByDefault: false),
Tables\Columns\TextColumn::make('created_by')
->label('Created By')
->alignCenter()
->sortable(),
Tables\Columns\TextColumn::make('updated_at')
->label('Updated At')
->alignCenter()
->dateTime()
->sortable()
->toggleable(isToggledHiddenByDefault: true),
Tables\Columns\TextColumn::make('updated_by')
->label('Updated By')
->alignCenter()
->sortable()
->toggleable(isToggledHiddenByDefault: true),
Tables\Columns\TextColumn::make('deleted_at')
->label('Deleted At')
->alignCenter()
->dateTime()
->sortable()
->toggleable(isToggledHiddenByDefault: true),
])
->filters([
Tables\Filters\TrashedFilter::make(),
])
->actions([
Tables\Actions\ViewAction::make(),
Tables\Actions\EditAction::make(),
])
->bulkActions([
Tables\Actions\BulkActionGroup::make([
Tables\Actions\DeleteBulkAction::make(),
Tables\Actions\ForceDeleteBulkAction::make(),
Tables\Actions\RestoreBulkAction::make(),
]),
]);
}
public static function getRelations(): array
{
return [
//
];
}
public static function getPages(): array
{
return [
'index' => Pages\ListAlertMailRules::route('/'),
'create' => Pages\CreateAlertMailRule::route('/create'),
'view' => Pages\ViewAlertMailRule::route('/{record}'),
'edit' => Pages\EditAlertMailRule::route('/{record}/edit'),
];
}
public static function getEloquentQuery(): Builder
{
return parent::getEloquentQuery()
->withoutGlobalScopes([
SoftDeletingScope::class,
]);
}
}

View File

@@ -0,0 +1,26 @@
<?php
namespace App\Filament\Resources\AlertMailRuleResource\Pages;
use App\Filament\Resources\AlertMailRuleResource;
use Filament\Actions;
use Filament\Resources\Pages\CreateRecord;
class CreateAlertMailRule extends CreateRecord
{
protected static string $resource = AlertMailRuleResource::class;
protected function mutateFormDataBeforeCreate(array $data): array
{
if ($data['is_active']) {
$data['plant'] = 0;
}
return $data;
}
protected function getRedirectUrl(): string
{
return $this->getResource()::getUrl('create');
}
}

View File

@@ -0,0 +1,31 @@
<?php
namespace App\Filament\Resources\AlertMailRuleResource\Pages;
use App\Filament\Resources\AlertMailRuleResource;
use Filament\Actions;
use Filament\Resources\Pages\EditRecord;
class EditAlertMailRule extends EditRecord
{
protected static string $resource = AlertMailRuleResource::class;
protected function mutateFormDataBeforeSave(array $data): array
{
//dd('test');
if ($data['is_active']) {
$data['plant'] = 0;
}
return $data;
}
protected function getHeaderActions(): array
{
return [
Actions\ViewAction::make(),
Actions\DeleteAction::make(),
Actions\ForceDeleteAction::make(),
Actions\RestoreAction::make(),
];
}
}

View File

@@ -0,0 +1,19 @@
<?php
namespace App\Filament\Resources\AlertMailRuleResource\Pages;
use App\Filament\Resources\AlertMailRuleResource;
use Filament\Actions;
use Filament\Resources\Pages\ListRecords;
class ListAlertMailRules extends ListRecords
{
protected static string $resource = AlertMailRuleResource::class;
protected function getHeaderActions(): array
{
return [
Actions\CreateAction::make(),
];
}
}

View File

@@ -0,0 +1,19 @@
<?php
namespace App\Filament\Resources\AlertMailRuleResource\Pages;
use App\Filament\Resources\AlertMailRuleResource;
use Filament\Actions;
use Filament\Resources\Pages\ViewRecord;
class ViewAlertMailRule extends ViewRecord
{
protected static string $resource = AlertMailRuleResource::class;
protected function getHeaderActions(): array
{
return [
Actions\EditAction::make(),
];
}
}

View File

@@ -0,0 +1,12 @@
<?php
namespace App\Filament\Resources\AppFilamentResourcesStickerMasterResource\Pages;
use App\Filament\Resources\AppFilamentResourcesStickerMasterResource;
use Filament\Actions;
use Filament\Resources\Pages\Create;
// class SubmitNameLabel extends Create
// {
// protected static string $resource = AppFilamentResourcesStickerMasterResource::class;
// }

View File

@@ -0,0 +1,207 @@
<?php
namespace App\Filament\Resources;
use App\Filament\Exports\BlockExporter;
use App\Filament\Imports\BlockImporter;
use App\Filament\Resources\BlockResource\Pages;
use App\Models\Block;
use App\Models\Plant;
use Filament\Facades\Filament;
use Filament\Forms;
use Filament\Forms\Form;
use Filament\Forms\Get;
use Filament\Resources\Resource;
use Filament\Tables;
use Filament\Tables\Actions\ImportAction;
use Filament\Tables\Table;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Database\Eloquent\SoftDeletingScope;
use Filament\Forms\Components\Section;
use Filament\Tables\Actions\ExportAction;
use Illuminate\Validation\Rule;
class BlockResource extends Resource
{
protected static ?string $model = Block::class;
protected static ?string $navigationIcon = 'heroicon-c-building-library';
protected static ?string $navigationGroup = 'Master Entries';
protected static ?int $navigationSort = 3;
public static function form(Form $form): Form
{
return $form
->schema([
Section::make('')
->schema([
Forms\Components\TextInput::make('name')
->required()
// ->unique(ignoreRecord: true)
->placeholder('Scan the valid name')
->autofocus(true)
->reactive()
->afterStateUpdated(function ($state, callable $set, callable $get) {
$nameId = $get('name');
// Ensure `linestop_id` is not cleared
if (!$nameId) {
$set('bNameError', 'Scan the valid name.');
return;
}
else
{
$set('bNameError', null);
}
})
->extraAttributes(fn ($get) => [
'class' => $get('bNameError') ? 'border-red-500' : '',
])
->hint(fn ($get) => $get('bNameError') ? $get('bNameError') : null)
->hintColor('danger')
->rule(function (callable $get) {
return Rule::unique('blocks', 'name')
->where('plant_id', $get('plant_id'))
->ignore($get('id')); // Ignore current record during updates
}),
Forms\Components\Select::make('plant_id')
->relationship('plant', 'name')
// ->unique(ignoreRecord: true)
->required()
->reactive()
->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();
})
->default(function () {
return optional(Block::latest()->first())->plant_id;
})
->disabled(fn (Get $get) => !empty($get('id')))
->afterStateUpdated(function ($state, callable $set, callable $get) {
$nameId = $get('plant_id');
// Ensure `linestop_id` is not cleared
if (!$nameId) {
$set('bPlantError', 'Please select a plant first.');
return;
}
else
{
$set('bPlantError', null);
}
})
->extraAttributes(fn ($get) => [
'class' => $get('bPlantError') ? 'border-red-500' : '',
])
->hint(fn ($get) => $get('bPlantError') ? $get('bPlantError') : null)
->hintColor('danger'),
Forms\Components\TextInput::make('id')
->hidden()
->readOnly(),
])
->columns(2),
]);
}
public static function table(Table $table): Table
{
return $table
->columns([
// Tables\Columns\TextColumn::make('id')
// ->label('ID')
// ->numeric()
// ->sortable(),
Tables\Columns\TextColumn::make('No.')
->label('No.')
->getStateUsing(function ($record, $livewire, $column, $rowLoop) {
$paginator = $livewire->getTableRecords();
$perPage = method_exists($paginator, 'perPage') ? $paginator->perPage() : 10;
$currentPage = method_exists($paginator, 'currentPage') ? $paginator->currentPage() : 1;
return ($currentPage - 1) * $perPage + $rowLoop->iteration;
}),
Tables\Columns\TextColumn::make('name')
//->unique(ignoreRecord: true)
->label('Block')
->alignCenter()
->sortable()
->searchable(),
Tables\Columns\TextColumn::make('plant.name')
->label('Plant')
->alignCenter()
->sortable()
->searchable(),
Tables\Columns\TextColumn::make('created_at')
->label('Created At')
->dateTime()
->alignCenter()
->sortable(),
Tables\Columns\TextColumn::make('updated_at')
->label('Updated At')
->dateTime()
->alignCenter()
->sortable()
->toggleable(isToggledHiddenByDefault: true),
Tables\Columns\TextColumn::make('deleted_at')
->label('Deleted At')
->dateTime()
->alignCenter()
->sortable()
->toggleable(isToggledHiddenByDefault: true),
])
->filters([
Tables\Filters\TrashedFilter::make(),
])
->actions([
Tables\Actions\ViewAction::make(),
Tables\Actions\EditAction::make(),
])
->bulkActions([
Tables\Actions\BulkActionGroup::make([
Tables\Actions\DeleteBulkAction::make(),
Tables\Actions\ForceDeleteBulkAction::make(),
Tables\Actions\RestoreBulkAction::make(),
]),
])
->headerActions([
ImportAction::make()
->label('Import Blocks')
->color('warning')
->importer(BlockImporter::class)
->visible(function() {
return Filament::auth()->user()->can('view import block');
}),
ExportAction::make()
->label('Export Blocks')
->color('warning')
->exporter(BlockExporter::class)
->visible(function() {
return Filament::auth()->user()->can('view export block');
}),
]);
}
public static function getRelations(): array
{
return [
//
];
}
public static function getPages(): array
{
return [
'index' => Pages\ListBlocks::route('/'),
'create' => Pages\CreateBlock::route('/create'),
'view' => Pages\ViewBlock::route('/{record}'),
'edit' => Pages\EditBlock::route('/{record}/edit'),
];
}
public static function getEloquentQuery(): Builder
{
return parent::getEloquentQuery()
->withoutGlobalScopes([
SoftDeletingScope::class,
]);
}
}

View File

@@ -0,0 +1,17 @@
<?php
namespace App\Filament\Resources\BlockResource\Pages;
use App\Filament\Resources\BlockResource;
use Filament\Actions;
use Filament\Resources\Pages\CreateRecord;
class CreateBlock extends CreateRecord
{
protected static string $resource = BlockResource::class;
protected function getRedirectUrl(): string
{
return $this->getResource()::getUrl('create');
}
}

View File

@@ -0,0 +1,22 @@
<?php
namespace App\Filament\Resources\BlockResource\Pages;
use App\Filament\Resources\BlockResource;
use Filament\Actions;
use Filament\Resources\Pages\EditRecord;
class EditBlock extends EditRecord
{
protected static string $resource = BlockResource::class;
protected function getHeaderActions(): array
{
return [
Actions\ViewAction::make(),
Actions\DeleteAction::make(),
Actions\ForceDeleteAction::make(),
Actions\RestoreAction::make(),
];
}
}

View File

@@ -0,0 +1,19 @@
<?php
namespace App\Filament\Resources\BlockResource\Pages;
use App\Filament\Resources\BlockResource;
use Filament\Actions;
use Filament\Resources\Pages\ListRecords;
class ListBlocks extends ListRecords
{
protected static string $resource = BlockResource::class;
protected function getHeaderActions(): array
{
return [
Actions\CreateAction::make(),
];
}
}

View File

@@ -0,0 +1,19 @@
<?php
namespace App\Filament\Resources\BlockResource\Pages;
use App\Filament\Resources\BlockResource;
use Filament\Actions;
use Filament\Resources\Pages\ViewRecord;
class ViewBlock extends ViewRecord
{
protected static string $resource = BlockResource::class;
protected function getHeaderActions(): array
{
return [
Actions\EditAction::make(),
];
}
}

View File

@@ -0,0 +1,50 @@
<?php
namespace App\Filament\Resources\BlockResource\RelationManagers;
use Filament\Forms;
use Filament\Forms\Form;
use Filament\Resources\RelationManagers\RelationManager;
use Filament\Tables;
use Filament\Tables\Table;
class BlocksRelationManager extends RelationManager
{
protected static string $relationship = 'blocks';
public function form(Form $form): Form
{
return $form
->schema([
Forms\Components\TextInput::make('name')
->required()
->maxLength(255),
]);
}
public function table(Table $table): Table
{
return $table
->recordTitleAttribute('name')
->columns([
Tables\Columns\TextColumn::make('name'),
// Tables\Columns\TextColumn::make('plants.name'),
])
->filters([
//
])
->headerActions([
Tables\Actions\CreateAction::make(),
])
->actions([
Tables\Actions\ViewAction::make(),
Tables\Actions\EditAction::make(),
Tables\Actions\DeleteAction::make(),
])
->bulkActions([
Tables\Actions\BulkActionGroup::make([
Tables\Actions\DeleteBulkAction::make(),
]),
]);
}
}

View File

@@ -0,0 +1,196 @@
<?php
namespace App\Filament\Resources;
use App\Filament\Exports\CheckPointNameExporter;
use App\Filament\Imports\CheckPointNameImporter;
use App\Filament\Resources\CheckPointNameResource\Pages;
use App\Filament\Resources\CheckPointNameResource\RelationManagers;
use App\Models\CheckPointName;
use App\Models\Plant;
use Filament\Facades\Filament;
use Filament\Forms;
use Filament\Forms\Form;
use Filament\Forms\Get;
use Filament\Resources\Resource;
use Filament\Tables;
use Filament\Tables\Actions\ExportAction;
use Filament\Tables\Actions\ImportAction;
use Filament\Tables\Table;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Database\Eloquent\SoftDeletingScope;
use Illuminate\Validation\Rule;
class CheckPointNameResource extends Resource
{
protected static ?string $model = CheckPointName::class;
protected static ?string $navigationIcon = 'heroicon-o-rectangle-stack';
protected static ?string $navigationGroup = 'Master Entries';
protected static ?int $navigationSort = 15;
public static function form(Form $form): Form
{
return $form
->schema([
Forms\Components\Select::make('plant_id')
->label('Plant')
->relationship('plant', 'name')
->required()
->reactive()
->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();
})
->default(function () {
return optional(CheckPointName::where('created_by', Filament::auth()->user()?->name)->latest()->first())->plant_id;
})
->disabled(fn (Get $get) => !empty($get('id')))
->afterStateUpdated(function ($state, callable $set, callable $get) {
$plantId = $get('plant_id');
if (!$plantId) {
$set('cPnPlantError', 'Please select a plant first.');
return;
}
else
{
$set('cPnPlantError', null);
$set('created_by', Filament::auth()->user()?->name);
}
})
->extraAttributes(fn ($get) => [
'class' => $get('cPnPlantError') ? 'border-red-500' : '',
])
->hint(fn ($get) => $get('cPnPlantError') ? $get('cPnPlantError') : null)
->hintColor('danger'),
Forms\Components\TextInput::make('name')
->label('Name')
->required()
->reactive()
->afterStateUpdated(function ($state, callable $set, callable $get) {
$set('created_by', Filament::auth()->user()?->name);
})
->rule(function (callable $get) {
return Rule::unique('check_point_names', 'name')
->where('plant_id', $get('plant_id'))
->ignore($get('id'));
}),
Forms\Components\Hidden::make('created_by')
->default(fn () => Filament::auth()->user()?->name)
->required(),
Forms\Components\TextInput::make('id')
->hidden()
->reactive()
->afterStateUpdated(function ($state, callable $set, callable $get) {
$set('created_by', Filament::auth()->user()?->name);
})
->readOnly(),
]);
}
public static function table(Table $table): Table
{
return $table
->columns([
Tables\Columns\TextColumn::make('No.')
->label('No.')
->getStateUsing(function ($record, $livewire, $column, $rowLoop) {
$paginator = $livewire->getTableRecords();
$perPage = method_exists($paginator, 'perPage') ? $paginator->perPage() : 10;
$currentPage = method_exists($paginator, 'currentPage') ? $paginator->currentPage() : 1;
return ($currentPage - 1) * $perPage + $rowLoop->iteration;
}),
// Tables\Columns\TextColumn::make('id')
// ->label('ID')
// ->numeric()
// ->sortable(),
Tables\Columns\TextColumn::make('plant.name')
->label('Plant')
->alignCenter()
->searchable()
->sortable(),
Tables\Columns\TextColumn::make('name')
->label('Check Point Name')
->alignCenter()
->searchable()
->sortable(),
Tables\Columns\TextColumn::make('created_at')
->label('Created At')
->dateTime()
->alignCenter()
->sortable(),
Tables\Columns\TextColumn::make('created_by')
->label('Created By')
->searchable()
->alignCenter(),
Tables\Columns\TextColumn::make('updated_at')
->label('Updated At')
->dateTime()
->alignCenter()
->sortable(),
Tables\Columns\TextColumn::make('deleted_at')
->label('Deleted At')
->dateTime()
->alignCenter()
->sortable()
->toggleable(isToggledHiddenByDefault: true),
])
->filters([
Tables\Filters\TrashedFilter::make(),
])
->actions([
Tables\Actions\ViewAction::make(),
Tables\Actions\EditAction::make(),
])
->bulkActions([
Tables\Actions\BulkActionGroup::make([
Tables\Actions\DeleteBulkAction::make(),
Tables\Actions\ForceDeleteBulkAction::make(),
Tables\Actions\RestoreBulkAction::make(),
]),
])
->headerActions([
ImportAction::make()
->label('Import Check Point Names')
->color('warning')
->importer(CheckPointNameImporter::class)
->visible(function() {
return Filament::auth()->user()->can('view import check point name');
}),
ExportAction::make()
->label('Export Check Point Names')
->color('warning')
->exporter(CheckPointNameExporter::class)
->visible(function() {
return Filament::auth()->user()->can('view export check point name');
}),
]);
}
public static function getRelations(): array
{
return [
//
];
}
public static function getPages(): array
{
return [
'index' => Pages\ListCheckPointNames::route('/'),
'create' => Pages\CreateCheckPointName::route('/create'),
'view' => Pages\ViewCheckPointName::route('/{record}'),
'edit' => Pages\EditCheckPointName::route('/{record}/edit'),
];
}
public static function getEloquentQuery(): Builder
{
return parent::getEloquentQuery()
->withoutGlobalScopes([
SoftDeletingScope::class,
]);
}
}

View File

@@ -0,0 +1,17 @@
<?php
namespace App\Filament\Resources\CheckPointNameResource\Pages;
use App\Filament\Resources\CheckPointNameResource;
use Filament\Actions;
use Filament\Resources\Pages\CreateRecord;
class CreateCheckPointName extends CreateRecord
{
protected static string $resource = CheckPointNameResource::class;
protected function getRedirectUrl(): string
{
return $this->getResource()::getUrl('create');
}
}

View File

@@ -0,0 +1,22 @@
<?php
namespace App\Filament\Resources\CheckPointNameResource\Pages;
use App\Filament\Resources\CheckPointNameResource;
use Filament\Actions;
use Filament\Resources\Pages\EditRecord;
class EditCheckPointName extends EditRecord
{
protected static string $resource = CheckPointNameResource::class;
protected function getHeaderActions(): array
{
return [
Actions\ViewAction::make(),
Actions\DeleteAction::make(),
Actions\ForceDeleteAction::make(),
Actions\RestoreAction::make(),
];
}
}

View File

@@ -0,0 +1,19 @@
<?php
namespace App\Filament\Resources\CheckPointNameResource\Pages;
use App\Filament\Resources\CheckPointNameResource;
use Filament\Actions;
use Filament\Resources\Pages\ListRecords;
class ListCheckPointNames extends ListRecords
{
protected static string $resource = CheckPointNameResource::class;
protected function getHeaderActions(): array
{
return [
Actions\CreateAction::make(),
];
}
}

View File

@@ -0,0 +1,19 @@
<?php
namespace App\Filament\Resources\CheckPointNameResource\Pages;
use App\Filament\Resources\CheckPointNameResource;
use Filament\Actions;
use Filament\Resources\Pages\ViewRecord;
class ViewCheckPointName extends ViewRecord
{
protected static string $resource = CheckPointNameResource::class;
protected function getHeaderActions(): array
{
return [
Actions\EditAction::make(),
];
}
}

View File

@@ -0,0 +1,427 @@
<?php
namespace App\Filament\Resources;
use App\Filament\Exports\CheckPointTimeExporter;
use App\Filament\Imports\CheckPointTimeImporter;
use App\Filament\Resources\CheckPointTimeResource\Pages;
use App\Filament\Resources\CheckPointTimeResource\RelationManagers;
use App\Models\CheckPointName;
use App\Models\CheckPointTime;
use App\Models\Plant;
use Filament\Facades\Filament;
use Filament\Forms;
use Filament\Forms\Form;
use Filament\Forms\Get;
use Filament\Resources\Resource;
use Filament\Tables;
use Filament\Tables\Actions\ExportAction;
use Filament\Tables\Actions\ImportAction;
use Filament\Tables\Table;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Database\Eloquent\SoftDeletingScope;
use Illuminate\Validation\Rule;
class CheckPointTimeResource extends Resource
{
protected static ?string $model = CheckPointTime::class;
protected static ?string $navigationIcon = 'heroicon-o-rectangle-stack';
protected static ?string $navigationGroup = 'Master Entries';
protected static ?int $navigationSort = 16;
public static function form(Form $form): Form
{
return $form
->schema([
Forms\Components\Select::make('plant_id')
->label('Plant')
->relationship('plant', 'name')
->required()
->reactive()
->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();
})
->default(function () {
return optional(CheckPointTime::where('created_by', Filament::auth()->user()?->name)->latest()->first())->plant_id;
})
->disabled(fn (Get $get) => !empty($get('id')))
->afterStateUpdated(function ($state, callable $set, callable $get) {
$plantId = $get('plant_id');
if (!$plantId) {
$set('cPtPlantError', 'Please select a plant first.');
return;
}
else
{
$set('cPtPlantError', null);
$set('created_by', Filament::auth()->user()?->name);
}
})
->extraAttributes(fn ($get) => [
'class' => $get('cPtPlantError') ? 'border-red-500' : '',
])
->hint(fn ($get) => $get('cPtPlantError') ? $get('cPtPlantError') : null)
->hintColor('danger'),
Forms\Components\TextInput::make('sequence_number')
->label('Sequence Number')
->required()
->reactive()
->integer()
->minValue(1)
->default(1)
->afterStateUpdated(function ($state, callable $set, callable $get) {
$set('created_by', Filament::auth()->user()?->name);
})
->rule(function (callable $get) {
return Rule::unique('check_point_times', 'sequence_number')
->where('plant_id', $get('plant_id'))
->ignore($get('id'));
//->where('check_point1_id', $get('check_point1_id'))
//->where('check_point2_id', $get('check_point2_id'))
}),
Forms\Components\Select::make('check_point1_id')
->label('Check Point Name 1')
// ->relationship('checkPointNames', 'name')
->options(function (callable $get) {
$plantId = $get('plant_id');
if (!$plantId) {
return [];
}
return CheckPointName::where('plant_id', $plantId)
->pluck('name', 'id')
->toArray();
})
->required()
->reactive()
->default(function () {
return optional(CheckPointTime::where('created_by', Filament::auth()->user()?->name)->latest()->first())->check_point1_id;
})
->disabled(fn (Get $get) => !empty($get('id')))
->afterStateUpdated(function ($state, callable $set, callable $get) {
$checkPoint1 = $get('check_point1_id');
$checkPoint2 = $get('check_point2_id');
if (!$checkPoint1) {
$set('cPtCheckPoint1Error', 'Please select a check point 1 first.');
return;
}
else
{
if ($checkPoint2 && $checkPoint1 == $checkPoint2) {
$set('cPtCheckPoint1Error', 'Duplicate check point 2 found.');
$set('check_point2_id', null);
return;
}
$set('cPtCheckPoint1Error', null);
$set('cPtCheckPoint2Error', null);
$set('created_by', Filament::auth()->user()?->name);
}
})
->extraAttributes(fn ($get) => [
'class' => $get('cPtCheckPoint1Error') ? 'border-red-500' : '',
])
->hint(fn ($get) => $get('cPtCheckPoint1Error') ? $get('cPtCheckPoint1Error') : null)
->hintColor('danger'),
Forms\Components\Select::make('check_point2_id')
->label('Check Point Name 2')
// ->relationship('checkPointNames', 'name')
->options(function (callable $get) {
$plantId = $get('plant_id');
if (!$plantId) {
return [];
}
return CheckPointName::where('plant_id', $plantId)
->pluck('name', 'id')
->toArray();
})
->required()
->reactive()
->default(function () {
return optional(CheckPointTime::where('created_by', Filament::auth()->user()?->name)->latest()->first())->check_point2_id;
})
->disabled(fn (Get $get) => !empty($get('id')))
->afterStateUpdated(function ($state, callable $set, callable $get) {
$checkPoint1 = $get('check_point1_id');
$checkPoint2 = $get('check_point2_id');
if (!$checkPoint2) {
$set('cPtCheckPoint2Error', 'Please select a check point 2 first.');
return;
}
else
{
if ($checkPoint1 && $checkPoint1 == $checkPoint2) {
$set('cPtCheckPoint2Error', 'Duplicate check point 2 found.');
$set('check_point2_id', null);
return;
}
$set('cPtCheckPoint1Error', null);
$set('cPtCheckPoint2Error', null);
$set('created_by', Filament::auth()->user()?->name);
}
})
->extraAttributes(fn ($get) => [
'class' => $get('cPtCheckPoint2Error') ? 'border-red-500' : '',
])
->hint(fn ($get) => $get('cPtCheckPoint2Error') ? $get('cPtCheckPoint2Error') : null)
->hintColor('danger')
->rule(function (callable $get) {
return Rule::unique('check_point_times', 'check_point2_id')
->where('check_point1_id', $get('check_point1_id'))
->where('plant_id', $get('plant_id'))
->ignore($get('id'));
}),
Forms\Components\TextInput::make('time_lapse')
->label('Time Lapse (in minutes)')
->required()
->integer()
->minValue(1)
->default(1)
->reactive()
->afterStateUpdated(function ($state, callable $set, callable $get) {
$timeLapse = $state;
$timeLapseCushioning = $get('time_lapse_cushioning');
if (!$timeLapse) {
$set('cPtTimeLapseError', 'Please enter a valid time lapse!');
$set('time_lapse_cushioning', null);
$set('min_cushioning', null);
$set('max_cushioning', null);
return;
}
elseif(!$timeLapseCushioning)
{
// $set('cPtTimeLapseError', 'Please enter a valid time lapse cushioning!');
$set('time_lapse_cushioning', 1);
$set('cPtTimeLapseError', null);
$set('min_cushioning', $timeLapse - 1);
$set('max_cushioning', $timeLapse + 1);
$set('created_by', Filament::auth()->user()?->name);
return;
}
elseif ($timeLapseCushioning > $timeLapse) {
$set('cPtTimeLapseError', 'Must be greater than or equal to time lapse cushioning!');
$set('time_lapse_cushioning', null);
$set('min_cushioning', null);
$set('max_cushioning', null);
return;
}
else
{
$set('cPtTimeLapseError', null);
$set('cPtTimeLapseCushError', null);
$set('min_cushioning', $timeLapse - $timeLapseCushioning);
$set('max_cushioning', $timeLapse + $timeLapseCushioning);
$set('created_by', Filament::auth()->user()?->name);
}
})
->extraAttributes(fn ($get) => [
'class' => $get('cPtTimeLapseError') ? 'border-red-500' : '',
])
->hint(fn ($get) => $get('cPtTimeLapseError') ? $get('cPtTimeLapseError') : null)
->hintColor('danger'),
Forms\Components\TextInput::make('time_lapse_cushioning')
->label('Time Lapse Cushioning (in minutes)')
->required()
->integer()
->minValue(1)
->default(1)
->reactive()
->afterStateUpdated(function ($state, callable $set, callable $get) {
$timeLapse = $get('time_lapse');
$timeLapseCushioning = $state;
if (!$timeLapse) {
$set('cPtTimeLapseCushError', 'Please enter a valid time lapse first.');
$set('time_lapse_cushioning', null);
$set('min_cushioning', null);
$set('max_cushioning', null);
return;
}
elseif(!$timeLapseCushioning)
{
// $set('cPtTimeLapseCushError', 'Please enter a valid time lapse cushioning!');
$set('time_lapse_cushioning', 1);
$set('cPtTimeLapseCushError', null);
$set('min_cushioning', $timeLapse - 1);
$set('max_cushioning', $timeLapse + 1);
$set('created_by', Filament::auth()->user()?->name);
return;
}
elseif ($timeLapseCushioning > $timeLapse) {
$set('cPtTimeLapseCushError', 'Must be less than or equal to time lapse!');
$set('time_lapse_cushioning', null);
$set('min_cushioning', null);
$set('max_cushioning', null);
return;
}
else
{
$set('cPtTimeLapseError', null);
$set('cPtTimeLapseCushError', null);
$set('min_cushioning', $timeLapse - $timeLapseCushioning);
$set('max_cushioning', $timeLapse + $timeLapseCushioning);
$set('created_by', Filament::auth()->user()?->name);
}
})
->extraAttributes(fn ($get) => [
'class' => $get('cPtTimeLapseCushError') ? 'border-red-500' : '',
])
->hint(fn ($get) => $get('cPtTimeLapseCushError') ? $get('cPtTimeLapseCushError') : null)
->hintColor('danger'),
Forms\Components\Hidden::make('min_cushioning')
->default(0)
->reactive()
->afterStateUpdated(function ($state, callable $set, callable $get) {
$set('created_by', Filament::auth()->user()?->name);
})
->required(),
Forms\Components\Hidden::make('max_cushioning')
->default(2)
->reactive()
->afterStateUpdated(function ($state, callable $set, callable $get) {
$set('created_by', Filament::auth()->user()?->name);
})
->required(),
Forms\Components\Hidden::make('created_by')
->default(fn () => Filament::auth()->user()?->name)
->required(),
Forms\Components\TextInput::make('id')
->hidden()
->reactive()
->afterStateUpdated(function ($state, callable $set, callable $get) {
$set('created_by', Filament::auth()->user()?->name);
})
->readOnly(),
]);
}
public static function table(Table $table): Table
{
return $table
->columns([
Tables\Columns\TextColumn::make('No.')
->label('No.')
->getStateUsing(function ($record, $livewire, $column, $rowLoop) {
$paginator = $livewire->getTableRecords();
$perPage = method_exists($paginator, 'perPage') ? $paginator->perPage() : 10;
$currentPage = method_exists($paginator, 'currentPage') ? $paginator->currentPage() : 1;
return ($currentPage - 1) * $perPage + $rowLoop->iteration;
}),
// Tables\Columns\TextColumn::make('id')
// ->label('ID')
// ->numeric()
// ->sortable(),
Tables\Columns\TextColumn::make('plant.name')
->label('Plant')
->alignCenter()
->searchable()
->sortable(),
Tables\Columns\TextColumn::make('checkPointNames1.name')
->label('Check Point 1')
->alignCenter()
->searchable()
->sortable(),
Tables\Columns\TextColumn::make('checkPointNames2.name')
->label('Check Point 2')
->alignCenter()
->searchable()
->sortable(),
Tables\Columns\TextColumn::make('sequence_number')
->label('Sequence Number')
->alignCenter()
->searchable()
->numeric()
->sortable(),
Tables\Columns\TextColumn::make('time_lapse')
->label('Time Lapse')
->alignCenter()
->searchable()
->numeric()
->sortable(),
Tables\Columns\TextColumn::make('time_lapse_cushioning')
->label('Time Lapse Cushioning (±)')
->alignCenter()
->searchable()
->numeric()
->sortable(),
Tables\Columns\TextColumn::make('created_at')
->label('Created At')
->dateTime()
->alignCenter()
->sortable(),
Tables\Columns\TextColumn::make('created_by')
->label('Created By')
->searchable()
->alignCenter(),
Tables\Columns\TextColumn::make('updated_at')
->label('Updated At')
->dateTime()
->alignCenter()
->sortable(),
Tables\Columns\TextColumn::make('deleted_at')
->label('Deleted At')
->dateTime()
->alignCenter()
->sortable()
->toggleable(isToggledHiddenByDefault: true),
])
->filters([
Tables\Filters\TrashedFilter::make(),
])
->actions([
Tables\Actions\ViewAction::make(),
Tables\Actions\EditAction::make(),
])
->bulkActions([
Tables\Actions\BulkActionGroup::make([
Tables\Actions\DeleteBulkAction::make(),
Tables\Actions\ForceDeleteBulkAction::make(),
Tables\Actions\RestoreBulkAction::make(),
]),
])
->headerActions([
ImportAction::make()
->label('Import Check Point Times')
->color('warning')
->importer(CheckPointTimeImporter::class)
->visible(function() {
return Filament::auth()->user()->can('view import check point time');
}),
ExportAction::make()
->label('Export Check Point Times')
->color('warning')
->exporter(CheckPointTimeExporter::class)
->visible(function() {
return Filament::auth()->user()->can('view export check point time');
}),
]);
}
public static function getRelations(): array
{
return [
//
];
}
public static function getPages(): array
{
return [
'index' => Pages\ListCheckPointTimes::route('/'),
'create' => Pages\CreateCheckPointTime::route('/create'),
'view' => Pages\ViewCheckPointTime::route('/{record}'),
'edit' => Pages\EditCheckPointTime::route('/{record}/edit'),
];
}
public static function getEloquentQuery(): Builder
{
return parent::getEloquentQuery()
->withoutGlobalScopes([
SoftDeletingScope::class,
]);
}
}

View File

@@ -0,0 +1,17 @@
<?php
namespace App\Filament\Resources\CheckPointTimeResource\Pages;
use App\Filament\Resources\CheckPointTimeResource;
use Filament\Actions;
use Filament\Resources\Pages\CreateRecord;
class CreateCheckPointTime extends CreateRecord
{
protected static string $resource = CheckPointTimeResource::class;
protected function getRedirectUrl(): string
{
return $this->getResource()::getUrl('create');
}
}

View File

@@ -0,0 +1,22 @@
<?php
namespace App\Filament\Resources\CheckPointTimeResource\Pages;
use App\Filament\Resources\CheckPointTimeResource;
use Filament\Actions;
use Filament\Resources\Pages\EditRecord;
class EditCheckPointTime extends EditRecord
{
protected static string $resource = CheckPointTimeResource::class;
protected function getHeaderActions(): array
{
return [
Actions\ViewAction::make(),
Actions\DeleteAction::make(),
Actions\ForceDeleteAction::make(),
Actions\RestoreAction::make(),
];
}
}

View File

@@ -0,0 +1,19 @@
<?php
namespace App\Filament\Resources\CheckPointTimeResource\Pages;
use App\Filament\Resources\CheckPointTimeResource;
use Filament\Actions;
use Filament\Resources\Pages\ListRecords;
class ListCheckPointTimes extends ListRecords
{
protected static string $resource = CheckPointTimeResource::class;
protected function getHeaderActions(): array
{
return [
Actions\CreateAction::make(),
];
}
}

View File

@@ -0,0 +1,19 @@
<?php
namespace App\Filament\Resources\CheckPointTimeResource\Pages;
use App\Filament\Resources\CheckPointTimeResource;
use Filament\Actions;
use Filament\Resources\Pages\ViewRecord;
class ViewCheckPointTime extends ViewRecord
{
protected static string $resource = CheckPointTimeResource::class;
protected function getHeaderActions(): array
{
return [
Actions\EditAction::make(),
];
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,12 @@
<?php
namespace App\Filament\Resources\ClassCharacteristicResource\Pages;
use App\Filament\Resources\ClassCharacteristicResource;
use Filament\Actions;
use Filament\Resources\Pages\CreateRecord;
class CreateClassCharacteristic extends CreateRecord
{
protected static string $resource = ClassCharacteristicResource::class;
}

View File

@@ -0,0 +1,22 @@
<?php
namespace App\Filament\Resources\ClassCharacteristicResource\Pages;
use App\Filament\Resources\ClassCharacteristicResource;
use Filament\Actions;
use Filament\Resources\Pages\EditRecord;
class EditClassCharacteristic extends EditRecord
{
protected static string $resource = ClassCharacteristicResource::class;
protected function getHeaderActions(): array
{
return [
Actions\ViewAction::make(),
Actions\DeleteAction::make(),
Actions\ForceDeleteAction::make(),
Actions\RestoreAction::make(),
];
}
}

View File

@@ -0,0 +1,19 @@
<?php
namespace App\Filament\Resources\ClassCharacteristicResource\Pages;
use App\Filament\Resources\ClassCharacteristicResource;
use Filament\Actions;
use Filament\Resources\Pages\ListRecords;
class ListClassCharacteristics extends ListRecords
{
protected static string $resource = ClassCharacteristicResource::class;
protected function getHeaderActions(): array
{
return [
Actions\CreateAction::make(),
];
}
}

View File

@@ -0,0 +1,19 @@
<?php
namespace App\Filament\Resources\ClassCharacteristicResource\Pages;
use App\Filament\Resources\ClassCharacteristicResource;
use Filament\Actions;
use Filament\Resources\Pages\ViewRecord;
class ViewClassCharacteristic extends ViewRecord
{
protected static string $resource = ClassCharacteristicResource::class;
protected function getHeaderActions(): array
{
return [
Actions\EditAction::make(),
];
}
}

View File

@@ -0,0 +1,163 @@
<?php
namespace App\Filament\Resources;
use App\Filament\Exports\CompanyExporter;
use App\Filament\Imports\CompanyImporter;
use App\Filament\Resources\CompanyResource\Pages;
use App\Filament\Resources\CompanyResource\RelationManagers\PlantsRelationManager;
use App\Models\Company;
use Filament\Actions\Imports\Importer;
use Filament\Facades\Filament;
use Filament\Forms;
use Filament\Forms\Form;
use Filament\Resources\Resource;
use Filament\Tables;
use Filament\Tables\Actions\ImportAction;
use Filament\Tables\Table;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Database\Eloquent\SoftDeletingScope;
use Filament\Forms\Components\Section;
use Filament\Tables\Actions\ExportAction;
class CompanyResource extends Resource
{
protected static ?string $model = Company::class;
protected static ?string $navigationIcon = 'heroicon-s-home-modern';
protected static ?string $navigationGroup = 'Master Entries';
protected static ?int $navigationSort = 1;
public static function form(Form $form): Form
{
return $form
->schema([
Section::make('')
->schema([
Forms\Components\TextInput::make('name')
->required()
//->citext('name')
->placeholder('Scan the valid name')
->autofocus(true)
->unique(ignoreRecord: true)
->columnSpanFull()
->reactive()
->afterStateUpdated(function ($state, callable $set, callable $get) {
$companyId = $get('name');
// Ensure `linestop_id` is not cleared
if (!$companyId) {
$set('cNameError', 'Scan the valid name first.');
return;
}
else
{
$set('cNameError', null);
}
})
->extraAttributes(fn ($get) => [
'class' => $get('cNameError') ? 'border-red-500' : '',
])
->hint(fn ($get) => $get('cNameError') ? $get('cNameError') : null)
->hintColor('danger'),
])
->columns(2),
]);
}
public static function table(Table $table): Table
{
return $table
->columns([
// Tables\Columns\TextColumn::make('id')
// ->label('ID')
// ->numeric()
// ->sortable(),
Tables\Columns\TextColumn::make('No.')
->label('No.')
->getStateUsing(function ($record, $livewire, $column, $rowLoop) {
$paginator = $livewire->getTableRecords();
$perPage = method_exists($paginator, 'perPage') ? $paginator->perPage() : 10;
$currentPage = method_exists($paginator, 'currentPage') ? $paginator->currentPage() : 1;
return ($currentPage - 1) * $perPage + $rowLoop->iteration;
}),
Tables\Columns\TextColumn::make('name')
->label('Company')
->alignCenter()
->sortable()
->searchable(),
Tables\Columns\TextColumn::make('created_at')
->label('Created At')
->dateTime()
->alignCenter()
->sortable(),
Tables\Columns\TextColumn::make('updated_at')
->label('Updated At')
->dateTime()
->alignCenter()
->sortable()
->toggleable(isToggledHiddenByDefault: true),
Tables\Columns\TextColumn::make('deleted_at')
->label('Deleted At')
->dateTime()
->alignCenter()
->sortable()
->toggleable(isToggledHiddenByDefault: true),
])
->filters([
Tables\Filters\TrashedFilter::make(),
])
->actions([
Tables\Actions\EditAction::make(),
Tables\Actions\ViewAction::make(),
])
->bulkActions([
Tables\Actions\BulkActionGroup::make([
Tables\Actions\DeleteBulkAction::make(),
Tables\Actions\ForceDeleteBulkAction::make(),
Tables\Actions\RestoreBulkAction::make(),
]),
])
->headerActions([
ImportAction::make()
->label('Import Companies')
->color('warning')
->importer(CompanyImporter::class)
->visible(function() {
return Filament::auth()->user()->can('view import company');
}),
ExportAction::make()
->label('Export Companies')
->color('warning')
->exporter(CompanyExporter::class)
->visible(function() {
return Filament::auth()->user()->can('view export company');
}),
]);
}
public static function getRelations(): array
{
return [
PlantsRelationManager::class,
];
}
public static function getPages(): array
{
return [
'index' => Pages\ListCompanies::route('/'),
'create' => Pages\CreateCompany::route('/create'),
'view' => Pages\ViewCompany::route('/{record}'),
'edit' => Pages\EditCompany::route('/{record}/edit'),
];
}
public static function getEloquentQuery(): Builder
{
return parent::getEloquentQuery()
->withoutGlobalScopes([
SoftDeletingScope::class,
]);
}
}

View File

@@ -0,0 +1,17 @@
<?php
namespace App\Filament\Resources\CompanyResource\Pages;
use App\Filament\Resources\CompanyResource;
use Filament\Actions;
use Filament\Resources\Pages\CreateRecord;
class CreateCompany extends CreateRecord
{
protected static string $resource = CompanyResource::class;
protected function getRedirectUrl(): string
{
return $this->getResource()::getUrl('create');
}
}

View File

@@ -0,0 +1,22 @@
<?php
namespace App\Filament\Resources\CompanyResource\Pages;
use App\Filament\Resources\CompanyResource;
use Filament\Actions;
use Filament\Resources\Pages\EditRecord;
class EditCompany extends EditRecord
{
protected static string $resource = CompanyResource::class;
protected function getHeaderActions(): array
{
return [
Actions\ViewAction::make(),
Actions\DeleteAction::make(),
Actions\ForceDeleteAction::make(),
Actions\RestoreAction::make(),
];
}
}

View File

@@ -0,0 +1,19 @@
<?php
namespace App\Filament\Resources\CompanyResource\Pages;
use App\Filament\Resources\CompanyResource;
use Filament\Actions;
use Filament\Resources\Pages\ListRecords;
class ListCompanies extends ListRecords
{
protected static string $resource = CompanyResource::class;
protected function getHeaderActions(): array
{
return [
Actions\CreateAction::make(),
];
}
}

View File

@@ -0,0 +1,19 @@
<?php
namespace App\Filament\Resources\CompanyResource\Pages;
use App\Filament\Resources\CompanyResource;
use Filament\Actions;
use Filament\Resources\Pages\ViewRecord;
class ViewCompany extends ViewRecord
{
protected static string $resource = CompanyResource::class;
protected function getHeaderActions(): array
{
return [
Actions\EditAction::make(),
];
}
}

View File

@@ -0,0 +1,52 @@
<?php
namespace App\Filament\Resources\CompanyResource\RelationManagers;
use Filament\Forms;
use Filament\Forms\Form;
use Filament\Resources\RelationManagers\RelationManager;
use Filament\Tables;
use Filament\Tables\Table;
class PlantsRelationManager extends RelationManager
{
protected static string $relationship = 'plants';
public function form(Form $form): Form
{
return $form
->schema([
Forms\Components\TextInput::make('name')
->required()
->maxLength(255),
]);
}
public function table(Table $table): Table
{
return $table
->recordTitleAttribute('name')
->columns([
Tables\Columns\TextColumn::make('name'),
Tables\Columns\TextColumn::make('code'),
Tables\Columns\TextColumn::make('address'),
])
->filters([
//
])
->headerActions([
Tables\Actions\CreateAction::make(),
])
->actions([
Tables\Actions\ViewAction::make(),
// ->url(fn () => route()),
Tables\Actions\EditAction::make(),
Tables\Actions\DeleteAction::make(),
])
->bulkActions([
Tables\Actions\BulkActionGroup::make([
Tables\Actions\DeleteBulkAction::make(),
]),
]);
}
}

View File

@@ -0,0 +1,226 @@
<?php
namespace App\Filament\Resources;
use App\Filament\Exports\ConfigurationExporter;
use App\Filament\Imports\ConfigurationImporter;
use App\Filament\Resources\ConfigurationResource\Pages;
use App\Filament\Resources\ConfigurationResource\RelationManagers;
use App\Models\Configuration;
use App\Models\Line;
use App\Models\Plant;
use Filament\Facades\Filament;
use Filament\Forms;
use Filament\Forms\Form;
use Filament\Forms\Get;
use Filament\Resources\Resource;
use Filament\Tables;
use Filament\Tables\Table;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Database\Eloquent\SoftDeletingScope;
use Filament\Tables\Actions\ImportAction;
use Filament\Tables\Actions\ExportAction;
class ConfigurationResource extends Resource
{
protected static ?string $model = Configuration::class;
protected static ?string $navigationIcon = 'heroicon-o-rectangle-stack';
protected static ?string $navigationGroup = 'Master Entries';
protected static ?int $navigationSort = 10;
public static function form(Form $form): Form
{
return $form
->schema([
Forms\Components\Select::make('plant_id')
->label('Plant')
->relationship('plant', 'name')
->required()
->reactive()
->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();
})
->default(function () {
return optional(Configuration::latest()->first())->plant_id;
})
->disabled(fn (Get $get) => !empty($get('id')))
->afterStateUpdated(function ($state, callable $set, callable $get) {
$plantId = $get('plant_id');
if (!$plantId) {
$set('cPlantError', 'Please select a plant first.');
return;
}
else
{
$set('cPlantError', null);
}
})
->extraAttributes(fn ($get) => [
'class' => $get('cPlantError') ? 'border-red-500' : '',
])
->hint(fn ($get) => $get('cPlantError') ? $get('cPlantError') : null)
->hintColor('danger'),
Forms\Components\Select::make('line_id')
->label('Line')
->relationship('line', 'name')
->required()
->reactive()
->options(function (callable $get) {
if (!$get('plant_id')) {
return [];
}
return Line::where('plant_id', $get('plant_id'))
->pluck('name', 'id')
->toArray();
})
->default(function () {
return optional(Configuration::latest()->first())->line_id;
})
->disabled(fn (Get $get) => !empty($get('id')))
->afterStateUpdated(function ($state, callable $set, callable $get) {
$lineId = $get('line_id');
if (!$lineId) {
$set('cLineError', 'Please select a line first.');
return;
}
else
{
$set('cLineError', null);
}
})
->extraAttributes(fn ($get) => [
'class' => $get('cLineError') ? 'border-red-500' : '',
])
->hint(fn ($get) => $get('cLineError') ? $get('cLineError') : null)
->hintColor('danger'),
Forms\Components\TextInput::make('c_type')
->label('Type')
->required(),
Forms\Components\TextInput::make('c_group')
->label('Group')
->required(),
Forms\Components\TextInput::make('c_name')
->label('Name')
->required(),
Forms\Components\TextInput::make('c_value')
->label('Value')
->required(),
Forms\Components\TextInput::make('id')
->hidden()
->readOnly(),
]);
}
public static function table(Table $table): Table
{
return $table
->columns([
Tables\Columns\TextColumn::make('No.')
->label('No.')
->getStateUsing(function ($record, $livewire, $column, $rowLoop) {
$paginator = $livewire->getTableRecords();
$perPage = method_exists($paginator, 'perPage') ? $paginator->perPage() : 10;
$currentPage = method_exists($paginator, 'currentPage') ? $paginator->currentPage() : 1;
return ($currentPage - 1) * $perPage + $rowLoop->iteration;
}),
Tables\Columns\TextColumn::make('plant.name')
->alignCenter()
->label('Plant')
->searchable(),
Tables\Columns\TextColumn::make('line.name')
->label('Line')
->alignCenter()
->searchable(),
Tables\Columns\TextColumn::make('c_type')
->label('Type')
->alignCenter()
->searchable(),
Tables\Columns\TextColumn::make('c_group')
->label('Group')
->alignCenter()
->searchable(),
Tables\Columns\TextColumn::make('c_name')
->label('Name')
->alignCenter()
->searchable(),
Tables\Columns\TextColumn::make('c_value')
->label('Value')
->alignCenter()
->searchable(),
Tables\Columns\TextColumn::make('created_at')
->label('Created At')
->dateTime()
->alignCenter()
->sortable(),
Tables\Columns\TextColumn::make('updated_at')
->dateTime()
->label('Updated At')
->alignCenter()
->sortable(),
Tables\Columns\TextColumn::make('deleted_at')
->dateTime()
->label('Deleted At')
->alignCenter()
->sortable()
->toggleable(isToggledHiddenByDefault: true),
])
->filters([
Tables\Filters\TrashedFilter::make(),
])
->actions([
Tables\Actions\ViewAction::make(),
Tables\Actions\EditAction::make(),
])
->bulkActions([
Tables\Actions\BulkActionGroup::make([
Tables\Actions\DeleteBulkAction::make(),
Tables\Actions\ForceDeleteBulkAction::make(),
Tables\Actions\RestoreBulkAction::make(),
]),
])
->headerActions([
ImportAction::make()
->label('Import Configurations')
->color('warning')
->importer(ConfigurationImporter::class)
->visible(function() {
return Filament::auth()->user()->can('view import configuration');
}),
ExportAction::make()
->label('Export Configurations')
->color('warning')
->exporter(ConfigurationExporter::class)
->visible(function() {
return Filament::auth()->user()->can('view export configuration');
}),
]);
}
public static function getRelations(): array
{
return [
//
];
}
public static function getPages(): array
{
return [
'index' => Pages\ListConfigurations::route('/'),
'create' => Pages\CreateConfiguration::route('/create'),
'view' => Pages\ViewConfiguration::route('/{record}'),
'edit' => Pages\EditConfiguration::route('/{record}/edit'),
];
}
public static function getEloquentQuery(): Builder
{
return parent::getEloquentQuery()
->withoutGlobalScopes([
SoftDeletingScope::class,
]);
}
}

View File

@@ -0,0 +1,17 @@
<?php
namespace App\Filament\Resources\ConfigurationResource\Pages;
use App\Filament\Resources\ConfigurationResource;
use Filament\Actions;
use Filament\Resources\Pages\CreateRecord;
class CreateConfiguration extends CreateRecord
{
protected static string $resource = ConfigurationResource::class;
protected function getRedirectUrl(): string
{
return $this->getResource()::getUrl('create');
}
}

View File

@@ -0,0 +1,22 @@
<?php
namespace App\Filament\Resources\ConfigurationResource\Pages;
use App\Filament\Resources\ConfigurationResource;
use Filament\Actions;
use Filament\Resources\Pages\EditRecord;
class EditConfiguration extends EditRecord
{
protected static string $resource = ConfigurationResource::class;
protected function getHeaderActions(): array
{
return [
Actions\ViewAction::make(),
Actions\DeleteAction::make(),
Actions\ForceDeleteAction::make(),
Actions\RestoreAction::make(),
];
}
}

View File

@@ -0,0 +1,19 @@
<?php
namespace App\Filament\Resources\ConfigurationResource\Pages;
use App\Filament\Resources\ConfigurationResource;
use Filament\Actions;
use Filament\Resources\Pages\ListRecords;
class ListConfigurations extends ListRecords
{
protected static string $resource = ConfigurationResource::class;
protected function getHeaderActions(): array
{
return [
Actions\CreateAction::make(),
];
}
}

View File

@@ -0,0 +1,19 @@
<?php
namespace App\Filament\Resources\ConfigurationResource\Pages;
use App\Filament\Resources\ConfigurationResource;
use Filament\Actions;
use Filament\Resources\Pages\ViewRecord;
class ViewConfiguration extends ViewRecord
{
protected static string $resource = ConfigurationResource::class;
protected function getHeaderActions(): array
{
return [
Actions\EditAction::make(),
];
}
}

View File

@@ -0,0 +1,160 @@
<?php
namespace App\Filament\Resources;
use App\Filament\Exports\DeviceMasterExporter;
use App\Filament\Imports\DeviceMasterImporter;
use App\Filament\Resources\DeviceMasterResource\Pages;
use App\Filament\Resources\DeviceMasterResource\RelationManagers;
use App\Models\DeviceMaster;
use App\Models\Plant;
use Filament\Facades\Filament;
use Filament\Forms;
use Filament\Forms\Form;
use Filament\Resources\Resource;
use Filament\Tables;
use Filament\Tables\Table;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Database\Eloquent\SoftDeletingScope;
use Filament\Forms\Components\Section;
use Filament\Tables\Actions\ImportAction;
use Filament\Tables\Actions\ExportAction;
class DeviceMasterResource extends Resource
{
protected static ?string $model = DeviceMaster::class;
protected static ?string $navigationIcon = 'heroicon-o-rectangle-stack';
protected static ?string $navigationGroup = 'Power House';
public static function form(Form $form): Form
{
return $form
->schema([
Section::make('')
->schema([
Forms\Components\Select::make('plant_id')
->label('Plant')
->relationship('plant', 'name')
->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(),
Forms\Components\TextInput::make('name')
->label('Device Name')
->required(),
Forms\Components\TextInput::make('mac_address')
->label('MAC Address'),
Forms\Components\TextInput::make('ip_address')
->label('IP Address'),
Forms\Components\Hidden::make('created_by')
->default(Filament::auth()->user()?->name),
])
->columns(4),
]);
}
public static function table(Table $table): Table
{
return $table
->columns([
Tables\Columns\TextColumn::make('No.')
->label('No.')
->getStateUsing(function ($record, $livewire, $column, $rowLoop) {
$paginator = $livewire->getTableRecords();
$perPage = method_exists($paginator, 'perPage') ? $paginator->perPage() : 10;
$currentPage = method_exists($paginator, 'currentPage') ? $paginator->currentPage() : 1;
return ($currentPage - 1) * $perPage + $rowLoop->iteration;
}),
Tables\Columns\TextColumn::make('plant.name')
->label('Plant')
->alignCenter()
->sortable(),
Tables\Columns\TextColumn::make('name')
->label('Device Name')
->alignCenter()
->sortable(),
Tables\Columns\TextColumn::make('mac_address')
->label('MAC Address')
->alignCenter()
->sortable(),
Tables\Columns\TextColumn::make('ip_address')
->label('IP Address')
->alignCenter()
->sortable(),
Tables\Columns\TextColumn::make('created_at')
->label('Created At')
->alignCenter()
->dateTime()
->sortable()
->toggleable(isToggledHiddenByDefault: true),
Tables\Columns\TextColumn::make('updated_at')
->label('Updated At')
->alignCenter()
->dateTime()
->sortable()
->toggleable(isToggledHiddenByDefault: true),
Tables\Columns\TextColumn::make('deleted_at')
->dateTime()
->alignCenter()
->sortable()
->toggleable(isToggledHiddenByDefault: true),
])
->filters([
Tables\Filters\TrashedFilter::make(),
])
->actions([
Tables\Actions\ViewAction::make(),
Tables\Actions\EditAction::make(),
])
->bulkActions([
Tables\Actions\BulkActionGroup::make([
Tables\Actions\DeleteBulkAction::make(),
Tables\Actions\ForceDeleteBulkAction::make(),
Tables\Actions\RestoreBulkAction::make(),
]),
])
->headerActions([
ImportAction::make()
->label('Import Device Masters')
->color('warning')
->importer(DeviceMasterImporter::class)
->visible(function() {
return Filament::auth()->user()->can('view import device master');
}),
ExportAction::make()
->label('Export Device Masters')
->color('warning')
->exporter(DeviceMasterExporter::class)
->visible(function() {
return Filament::auth()->user()->can('view export device master');
}),
]);
}
public static function getRelations(): array
{
return [
//
];
}
public static function getPages(): array
{
return [
'index' => Pages\ListDeviceMasters::route('/'),
'create' => Pages\CreateDeviceMaster::route('/create'),
'view' => Pages\ViewDeviceMaster::route('/{record}'),
'edit' => Pages\EditDeviceMaster::route('/{record}/edit'),
];
}
public static function getEloquentQuery(): Builder
{
return parent::getEloquentQuery()
->withoutGlobalScopes([
SoftDeletingScope::class,
]);
}
}

View File

@@ -0,0 +1,17 @@
<?php
namespace App\Filament\Resources\DeviceMasterResource\Pages;
use App\Filament\Resources\DeviceMasterResource;
use Filament\Actions;
use Filament\Resources\Pages\CreateRecord;
class CreateDeviceMaster extends CreateRecord
{
protected static string $resource = DeviceMasterResource::class;
protected function getRedirectUrl(): string
{
return $this->getResource()::getUrl('create');
}
}

View File

@@ -0,0 +1,22 @@
<?php
namespace App\Filament\Resources\DeviceMasterResource\Pages;
use App\Filament\Resources\DeviceMasterResource;
use Filament\Actions;
use Filament\Resources\Pages\EditRecord;
class EditDeviceMaster extends EditRecord
{
protected static string $resource = DeviceMasterResource::class;
protected function getHeaderActions(): array
{
return [
Actions\ViewAction::make(),
Actions\DeleteAction::make(),
Actions\ForceDeleteAction::make(),
Actions\RestoreAction::make(),
];
}
}

View File

@@ -0,0 +1,19 @@
<?php
namespace App\Filament\Resources\DeviceMasterResource\Pages;
use App\Filament\Resources\DeviceMasterResource;
use Filament\Actions;
use Filament\Resources\Pages\ListRecords;
class ListDeviceMasters extends ListRecords
{
protected static string $resource = DeviceMasterResource::class;
protected function getHeaderActions(): array
{
return [
Actions\CreateAction::make(),
];
}
}

View File

@@ -0,0 +1,19 @@
<?php
namespace App\Filament\Resources\DeviceMasterResource\Pages;
use App\Filament\Resources\DeviceMasterResource;
use Filament\Actions;
use Filament\Resources\Pages\ViewRecord;
class ViewDeviceMaster extends ViewRecord
{
protected static string $resource = DeviceMasterResource::class;
protected function getHeaderActions(): array
{
return [
Actions\EditAction::make(),
];
}
}

View File

@@ -0,0 +1,243 @@
<?php
namespace App\Filament\Resources;
use App\Filament\Resources\DriverMasterResource\Pages;
use App\Filament\Resources\DriverMasterResource\RelationManagers;
use App\Models\DriverMaster;
use Filament\Facades\Filament;
use Filament\Forms;
use Filament\Forms\Components\TextInput;
use Filament\Forms\Form;
use Filament\Resources\Resource;
use Filament\Tables;
use Filament\Tables\Table;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Database\Eloquent\SoftDeletingScope;
use Filament\Forms\Components\Actions;
use Filament\Forms\Components\Actions\Action;
use Filament\Notifications\Notification;
use League\Flysystem\Filesystem;
use League\Flysystem\FilesystemAdapter;
use League\Flysystem\Sftp\SftpAdapter;
use phpseclib3\Net\SFTP;
class DriverMasterResource extends Resource
{
protected static ?string $model = DriverMaster::class;
protected static ?string $navigationIcon = 'heroicon-o-rectangle-stack';
protected static ?string $navigationGroup = 'Transport Tracking';
public static function form(Form $form): Form
{
return $form
->schema([
Forms\Components\TextInput::make('name')
->label('Name')
->required(),
Forms\Components\TextInput::make('identification1')
->label('Aadhar Number')
->required(),
Forms\Components\TextInput::make('identification2')
->label('Driving License Number')
->required(),
Forms\Components\TextInput::make('identification3')
->label('PAN Number'),
Forms\Components\TextInput::make('contact_number')
->label('Contact Number')
->required(),
Forms\Components\TextInput::make('alternate_number')
->label('Alternate Number'),
// Forms\Components\TextInput::make('file_name')
// ->label('File Name')
// ->placeholder('Enter file name without extension')
// ->required()
// ->reactive()
// ->extraAttributes([
// 'onkeydown' => 'if(event.key == "Enter"){ event.preventDefault(); openFileDialog(); }',
// ]),
// Forms\Components\Actions::make([
// Action::make('read_folder')
// ->label('Read Folder')
// ->icon('heroicon-o-folder')
// ->color('info')
// //->extraAttributes(['onclick' => 'openFolderPicker()']),
// ->extraAttributes(['onclick' => 'openFileDialog()']),
// ]),
TextInput::make('file_name')
->label('File Name')
->required()
->reactive()
->extraAttributes([
'x-data' => '{ value: "" }',
'x-model' => 'value',
'x-on:keydown.enter.prevent' => '$wire.process(value)',
]),
// Filament Action inside your form/page
Actions::make([
Action::make('read_file')
->label('Read File')
//->hidden()
->action(function ($get) {
$fileName = $get('file_name');
if (!$fileName) {
Notification::make()
->title('File name is required!')
->danger()
->send();
return;
}
$ftpHost = env('SFTP_HOST');
$ftpUser = env('SFTP_USERNAME');
$ftpPass = env('SFTP_PASSWORD');
$remoteDir = env('SFTP_ROOT');
$port = env('SFTP_PORT');
$sftp = new SFTP($ftpHost, $port, 10);
if (! $sftp->login($ftpUser, $ftpPass)) {
Notification::make()->title('SFTP login failed')->danger()->send();
return;
}
// $files = $sftp->nlist();
// dd($files);
$remoteFile = $remoteDir . '/' . $fileName . '.txt';
$content = $sftp->get($remoteFile);
if ($content == false) {
Notification::make()
->title("File {$remoteFile} not found")
->danger()
->send();
return;
}
if ($content == false) {
Notification::make()
->title("Failed to read {$remoteDir} from SFTP")
->danger()
->send();
return;
}
$lines = array_map('trim', explode("\n", str_replace("\r", "", $content)));
DriverMaster::create([
'name' => $lines[0] ?? '',
'identification1' => $lines[1] ?? '',
'identification2' => $lines[2] ?? '',
'identification3' => $lines[3] ?? '',
'contact_number' => $lines[4] ?? '',
'alternate_number' => $lines[5] ?? '',
]);
Notification::make()
->title("File {$remoteDir} read and saved successfully!")
->success()
->send();
}),
]),
Forms\Components\Hidden::make('created_by')
->required()
->default(Filament::auth()->user()?->name),
]);
}
public static function table(Table $table): Table
{
return $table
->columns([
Tables\Columns\TextColumn::make('No.')
->label('No.')
->getStateUsing(function ($record, $livewire, $column, $rowLoop) {
$paginator = $livewire->getTableRecords();
$perPage = method_exists($paginator, 'perPage') ? $paginator->perPage() : 10;
$currentPage = method_exists($paginator, 'currentPage') ? $paginator->currentPage() : 1;
return ($currentPage - 1) * $perPage + $rowLoop->iteration;
}),
Tables\Columns\TextColumn::make('name')
->label('Name')
->alignCenter()
->sortable(),
Tables\Columns\TextColumn::make('identification1')
->label('Aadhar Number')
->alignCenter()
->sortable(),
Tables\Columns\TextColumn::make('identification2')
->label('Driving License Number')
->alignCenter()
->sortable(),
Tables\Columns\TextColumn::make('identification3')
->label('PAN Number')
->alignCenter()
->sortable(),
Tables\Columns\TextColumn::make('contact_number')
->label('Contact Number')
->alignCenter()
->sortable(),
Tables\Columns\TextColumn::make('alternate_number')
->label('Alternate Number')
->alignCenter()
->sortable(),
Tables\Columns\TextColumn::make('created_at')
->dateTime()
->sortable()
->toggleable(isToggledHiddenByDefault: true),
Tables\Columns\TextColumn::make('updated_at')
->dateTime()
->sortable()
->toggleable(isToggledHiddenByDefault: true),
Tables\Columns\TextColumn::make('deleted_at')
->dateTime()
->sortable()
->toggleable(isToggledHiddenByDefault: true),
])
->filters([
Tables\Filters\TrashedFilter::make(),
])
->actions([
Tables\Actions\ViewAction::make(),
Tables\Actions\EditAction::make(),
])
->bulkActions([
Tables\Actions\BulkActionGroup::make([
Tables\Actions\DeleteBulkAction::make(),
Tables\Actions\ForceDeleteBulkAction::make(),
Tables\Actions\RestoreBulkAction::make(),
]),
]);
}
public static function getRelations(): array
{
return [
//
];
}
public static function getPages(): array
{
return [
'index' => Pages\ListDriverMasters::route('/'),
'create' => Pages\CreateDriverMaster::route('/create'),
'view' => Pages\ViewDriverMaster::route('/{record}'),
'edit' => Pages\EditDriverMaster::route('/{record}/edit'),
];
}
public static function getEloquentQuery(): Builder
{
return parent::getEloquentQuery()
->withoutGlobalScopes([
SoftDeletingScope::class,
]);
}
}

View File

@@ -0,0 +1,75 @@
<?php
namespace App\Filament\Resources\DriverMasterResource\Pages;
use App\Filament\Resources\DriverMasterResource;
use App\Models\DriverMaster;
use Filament\Actions;
use Filament\Notifications\Notification;
use Filament\Resources\Pages\CreateRecord;
use phpseclib3\Net\SFTP;
class CreateDriverMaster extends CreateRecord
{
protected static string $resource = DriverMasterResource::class;
public function process($fileName)
{
//$file = trim($fileName);
if (!$fileName)
{
Notification::make()
->title('File name is required!')
->danger()
->send();
return;
}
$ftpHost = env('SFTP_HOST');
$ftpUser = env('SFTP_USERNAME');
$ftpPass = env('SFTP_PASSWORD');
$remoteDir = env('SFTP_ROOT');
$port = env('SFTP_PORT');
$sftp = new SFTP($ftpHost, $port, 10);
if (! $sftp->login($ftpUser, $ftpPass)) {
Notification::make()->title('SFTP login failed')->danger()->send();
return;
}
$remoteFile = $remoteDir . '/' . $fileName . '.txt';
$content = $sftp->get($remoteFile);
if ($content == false) {
Notification::make()
->title("File {$remoteFile} not found")
->danger()
->send();
return;
}
if ($content == false) {
Notification::make()
->title("Failed to read {$remoteDir} from SFTP")
->danger()
->send();
return;
}
$lines = array_map('trim', explode("\n", str_replace("\r", "", $content)));
DriverMaster::create([
'name' => $lines[0] ?? '',
'identification1' => $lines[1] ?? '',
'identification2' => $lines[2] ?? '',
'identification3' => $lines[3] ?? '',
'contact_number' => $lines[4] ?? '',
'alternate_number' => $lines[5] ?? '',
]);
Notification::make()
->title("File {$remoteDir} read and saved successfully!")
->success()
->send();
}
}

View File

@@ -0,0 +1,22 @@
<?php
namespace App\Filament\Resources\DriverMasterResource\Pages;
use App\Filament\Resources\DriverMasterResource;
use Filament\Actions;
use Filament\Resources\Pages\EditRecord;
class EditDriverMaster extends EditRecord
{
protected static string $resource = DriverMasterResource::class;
protected function getHeaderActions(): array
{
return [
Actions\ViewAction::make(),
Actions\DeleteAction::make(),
Actions\ForceDeleteAction::make(),
Actions\RestoreAction::make(),
];
}
}

View File

@@ -0,0 +1,19 @@
<?php
namespace App\Filament\Resources\DriverMasterResource\Pages;
use App\Filament\Resources\DriverMasterResource;
use Filament\Actions;
use Filament\Resources\Pages\ListRecords;
class ListDriverMasters extends ListRecords
{
protected static string $resource = DriverMasterResource::class;
protected function getHeaderActions(): array
{
return [
Actions\CreateAction::make(),
];
}
}

View File

@@ -0,0 +1,19 @@
<?php
namespace App\Filament\Resources\DriverMasterResource\Pages;
use App\Filament\Resources\DriverMasterResource;
use Filament\Actions;
use Filament\Resources\Pages\ViewRecord;
class ViewDriverMaster extends ViewRecord
{
protected static string $resource = DriverMasterResource::class;
protected function getHeaderActions(): array
{
return [
Actions\EditAction::make(),
];
}
}

View File

@@ -0,0 +1,455 @@
<?php
namespace App\Filament\Resources;
use App\Filament\Exports\EbReadingExporter;
use App\Filament\Imports\EbReadingImporter;
use App\Filament\Resources\EbReadingResource\Pages;
use App\Filament\Resources\EbReadingResource\RelationManagers;
use App\Models\EbReading;
use App\Models\Plant;
use Filament\Forms;
use Filament\Forms\Form;
use Filament\Resources\Resource;
use Filament\Tables;
use Filament\Tables\Table;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Database\Eloquent\SoftDeletingScope;
use Filament\Tables\Actions\ImportAction;
use Filament\Tables\Actions\ExportAction;
use Filament\Facades\Filament;
use Filament\Tables\Filters\Filter;
use Filament\Forms\Components\Select;
use Filament\Forms\Components\TextInput;
use Filament\Forms\Components\DateTimePicker;
class EbReadingResource extends Resource
{
protected static ?string $model = EbReading::class;
protected static ?string $navigationIcon = 'heroicon-o-rectangle-stack';
protected static ?string $navigationGroup = 'Power House';
public static function form(Form $form): Form
{
return $form
->schema([
Forms\Components\Select::make('plant_id')
->relationship('plant', 'name')
->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(),
Forms\Components\TextInput::make('lcd_segment_check')
->label('LCD Segment Check'),
Forms\Components\TextInput::make('meter_serial_no')
->label('Meter Serial No'),
Forms\Components\DateTimePicker::make('eb_date_time')
->required()
->label('EB Date Time'),
Forms\Components\TextInput::make('ph_seq_of_volt')
->label('PH Sequence of Volt'),
Forms\Components\TextInput::make('ph_assoc_conn_check')
->label('PH Association Connection Check'),
Forms\Components\TextInput::make('instantaneous_ph_volt')
->label('Instantaneous PH Volt'),
Forms\Components\TextInput::make('instantaneous_curr')
->label('Instantaneous Current'),
Forms\Components\TextInput::make('instantaneous_freq')
->label('Instantaneous Frequency'),
Forms\Components\TextInput::make('instantaneous_kw_with_sign')
->label('Instantaneous KW with Sign'),
Forms\Components\TextInput::make('instantaneous_kva')
->label('Instantaneous KVA'),
Forms\Components\TextInput::make('instantaneous_kv_ar')
->label('Instantaneous KV AR'),
Forms\Components\TextInput::make('instantaneous_pf_with_sign')
->label('Instantaneous PF with Sign'),
Forms\Components\TextInput::make('rd_with_elapsed_time_kva')
->label('RD with Elapsed Time KVA'),
Forms\Components\TextInput::make('cum_active_import_energy')
->label('Cumulative Active Import Energy'),
Forms\Components\TextInput::make('tod1_active_energy_6_9')
->label('TOD1 Active Energy 6-9'),
Forms\Components\TextInput::make('tod2_active_energy_18_21')
->label('TOD2 Active Energy 18-21'),
Forms\Components\TextInput::make('tod3_active_energy_21_22')
->label('TOD3 Active Energy 21-22'),
Forms\Components\TextInput::make('tod4_active_energy_5_6_9_18')
->label('TOD4 Active Energy 5-6-9-18'),
Forms\Components\TextInput::make('tod5_active_energy_22_5')
->label('TOD5 Active Energy 22-5'),
Forms\Components\TextInput::make('cum_reac_lag_energy')
->label('Cumulative Reactive Lag Energy'),
Forms\Components\TextInput::make('cum_reac_lead_energy')
->label('Cumulative Reactive Lead Energy'),
Forms\Components\TextInput::make('cum_appar_energy')
->label('Cumulative Apparent Energy'),
Forms\Components\TextInput::make('tod1_appar_energy_6_9')
->label('TOD1 Apparent Energy 6-9'),
Forms\Components\TextInput::make('tod2_appar_energy_18_21')
->label('TOD2 Apparent Energy 18-21'),
Forms\Components\TextInput::make('tod3_appar_energy_21_22')
->label('TOD3 Apparent Energy 21-22'),
Forms\Components\TextInput::make('tod4_appar_energy_5_6_9_18')
->label('TOD4 Apparent Energy 5-6-9-18'),
Forms\Components\TextInput::make('tod5_appar_energy_22_5')
->label('TOD5 Apparent Energy 22-5'),
Forms\Components\TextInput::make('avg_pow_factor')
->label('Average Power Factor'),
Forms\Components\TextInput::make('avg_freq_15min_last_ip')
->label('Average Frequency 15min Last IP'),
Forms\Components\TextInput::make('net_kv_arh_high')
->label('Net KV ARH High'),
Forms\Components\TextInput::make('net_kv_arh_low')
->label('Net KV ARH Low'),
Forms\Components\TextInput::make('cum_md_kva')
->label('Cumulative MD KVA'),
Forms\Components\TextInput::make('present_md_kva')
->label('Present MD KVA'),
Forms\Components\DateTimePicker::make('present_md_kva_date_time')
->label('Present MD KVA Date Time')
->required(),
Forms\Components\TextInput::make('tod1_md_kva_6_9')
->label('TOD1 MD KVA 6-9'),
Forms\Components\TextInput::make('tod2_md_kva_18_21')
->label('TOD2 MD KVA 18-21'),
Forms\Components\TextInput::make('tod3_md_kva_21_22')
->label('TOD3 MD KVA 21-22'),
Forms\Components\TextInput::make('tod4_md_kva_5_6_9_18')
->label('TOD4 MD KVA 5-6-9-18'),
Forms\Components\TextInput::make('tod5_md_kva_22_5')
->label('TOD5 MD KVA 22-5'),
Forms\Components\TextInput::make('total_pow_off_hours')
->label('Total Power Off Hours'),
Forms\Components\TextInput::make('programming_count')
->label('Programming Count'),
Forms\Components\TextInput::make('last_occ_res_event_type')
->label('Last Occurrence/Reset Event Type'),
Forms\Components\DateTimePicker::make('last_occ_res_event_date_time')
->label('Last Occurrence/Reset Event Date Time')
->required(),
Forms\Components\TextInput::make('tamper_count')
->label('Tamper Count'),
Forms\Components\TextInput::make('reset_count')
->label('Reset Count'),
Forms\Components\DateTimePicker::make('last_md_reset_date_time')
->label('Last MD Reset Date Time')
->required(),
Forms\Components\Hidden::make('electrician_sign')
->default(Filament::auth()->user()?->name),
]);
}
public static function table(Table $table): Table
{
return $table
->columns([
Tables\Columns\TextColumn::make('No.')
->label('No.')
->alignCenter()
->getStateUsing(function ($record, $livewire, $column, $rowLoop) {
$paginator = $livewire->getTableRecords();
$perPage = method_exists($paginator, 'perPage') ? $paginator->perPage() : 10;
$currentPage = method_exists($paginator, 'currentPage') ? $paginator->currentPage() : 1;
return ($currentPage - 1) * $perPage + $rowLoop->iteration;
}),
Tables\Columns\TextColumn::make('plant.name')
->label('Plant')
->alignCenter()
->sortable(),
Tables\Columns\TextColumn::make('lcd_segment_check')
->alignCenter()
->label('LCD Segment Check'),
Tables\Columns\TextColumn::make('meter_serial_no')
->alignCenter()
->label('Meter Serial No'),
Tables\Columns\TextColumn::make('eb_date_time')
->alignCenter()
->label('EB Date Time'),
Tables\Columns\TextColumn::make('ph_seq_of_volt')
->alignCenter()
->label('PH Sequence of Volt'),
Tables\Columns\TextColumn::make('ph_assoc_conn_check')
->alignCenter()
->label('PH Association Connection Check'),
Tables\Columns\TextColumn::make('instantaneous_ph_volt')
->alignCenter()
->label('Instantaneous PH Volt'),
Tables\Columns\TextColumn::make('instantaneous_curr')
->alignCenter()
->label('Instantaneous Current'),
Tables\Columns\TextColumn::make('instantaneous_freq')
->alignCenter()
->label('Instantaneous Frequency'),
Tables\Columns\TextColumn::make('instantaneous_kw_with_sign')
->alignCenter()
->label('Instantaneous KW with Sign'),
Tables\Columns\TextColumn::make('instantaneous_kva')
->alignCenter()
->label('Instantaneous KVA'),
Tables\Columns\TextColumn::make('instantaneous_kv_ar')
->alignCenter()
->label('Instantaneous KV AR'),
Tables\Columns\TextColumn::make('instantaneous_pf_with_sign')
->alignCenter()
->label('Instantaneous PF with Sign'),
Tables\Columns\TextColumn::make('rd_with_elapsed_time_kva')
->alignCenter()
->label('RD with Elapsed Time KVA'),
Tables\Columns\TextColumn::make('cum_active_import_energy')
->alignCenter()
->label('Cumulative Active Import Energy'),
Tables\Columns\TextColumn::make('tod1_active_energy_6_9')
->alignCenter()
->label('TOD1 Active Energy 6-9'),
Tables\Columns\TextColumn::make('tod2_active_energy_18_21')
->alignCenter()
->label('TOD2 Active Energy 18-21'),
Tables\Columns\TextColumn::make('tod3_active_energy_21_22')
->alignCenter()
->label('TOD3 Active Energy 21-22'),
Tables\Columns\TextColumn::make('tod4_active_energy_5_6_9_18')
->alignCenter()
->label('TOD4 Active Energy 5-6-9-18'),
Tables\Columns\TextColumn::make('tod5_active_energy_22_5')
->alignCenter()
->label('TOD5 Active Energy 22-5'),
Tables\Columns\TextColumn::make('cum_reac_lag_energy')
->alignCenter()
->label('Cumulative Reactive Lag Energy'),
Tables\Columns\TextColumn::make('cum_reac_lead_energy')
->alignCenter()
->label('Cumulative Reactive Lead Energy'),
Tables\Columns\TextColumn::make('cum_appar_energy')
->alignCenter()
->label('Cumulative Apparent Energy'),
Tables\Columns\TextColumn::make('tod1_appar_energy_6_9')
->alignCenter()
->label('TOD1 Apparent Energy 6-9'),
Tables\Columns\TextColumn::make('tod2_appar_energy_18_21')
->alignCenter()
->label('TOD2 Apparent Energy 18-21'),
Tables\Columns\TextColumn::make('tod3_appar_energy_21_22')
->alignCenter()
->label('TOD3 Apparent Energy 21-22'),
Tables\Columns\TextColumn::make('tod4_appar_energy_5_6_9_18')
->alignCenter()
->label('TOD4 Apparent Energy 5-6-9-18'),
Tables\Columns\TextColumn::make('tod5_appar_energy_22_5')
->alignCenter()
->label('TOD5 Apparent Energy 22-5'),
Tables\Columns\TextColumn::make('avg_pow_factor')
->alignCenter()
->label('Average Power Factor'),
Tables\Columns\TextColumn::make('avg_freq_15min_last_ip')
->alignCenter()
->label('Average Frequency 15min Last IP'),
Tables\Columns\TextColumn::make('net_kv_arh_high')
->alignCenter()
->label('Net KV ARH High'),
Tables\Columns\TextColumn::make('net_kv_arh_low')
->alignCenter()
->label('Net KV ARH Low'),
Tables\Columns\TextColumn::make('cum_md_kva')
->alignCenter()
->label('Cumulative MD KVA'),
Tables\Columns\TextColumn::make('present_md_kva')
->alignCenter()
->label('Present MD KVA'),
Tables\Columns\TextColumn::make('present_md_kva_date_time')
->alignCenter()
->label('Present MD KVA Date Time'),
Tables\Columns\TextColumn::make('tod1_md_kva_6_9')
->alignCenter()
->label('TOD1 MD KVA 6-9'),
Tables\Columns\TextColumn::make('tod2_md_kva_18_21')
->alignCenter()
->label('TOD2 MD KVA 18-21'),
Tables\Columns\TextColumn::make('tod3_md_kva_21_22')
->alignCenter()
->label('TOD3 MD KVA 21-22'),
Tables\Columns\TextColumn::make('tod4_md_kva_5_6_9_18')
->alignCenter()
->label('TOD4 MD KVA 5-6-9-18'),
Tables\Columns\TextColumn::make('tod5_md_kva_22_5')
->alignCenter()
->label('TOD5 MD KVA 22-5'),
Tables\Columns\TextColumn::make('total_pow_off_hours')
->alignCenter()
->label('Total Power Off Hours'),
Tables\Columns\TextColumn::make('programming_count')
->alignCenter()
->label('Programming Count'),
Tables\Columns\TextColumn::make('last_occ_res_event_type')
->alignCenter()
->label('Last Occurrence/Reset Event Type'),
Tables\Columns\TextColumn::make('last_occ_res_event_date_time')
->alignCenter()
->label('Last Occurrence/Reset Event Date Time'),
Tables\Columns\TextColumn::make('tamper_count')
->alignCenter()
->label('Tamper Count'),
Tables\Columns\TextColumn::make('reset_count')
->alignCenter()
->label('Reset Count'),
Tables\Columns\TextColumn::make('last_md_reset_date_time')
->alignCenter()
->label('Last MD Reset Date Time'),
Tables\Columns\TextColumn::make('electrician_sign')
->alignCenter()
->label('Created By'),
Tables\Columns\TextColumn::make('created_at')
->alignCenter()
->label('Created At')
->dateTime()
->sortable()
->toggleable(isToggledHiddenByDefault: true),
Tables\Columns\TextColumn::make('updated_at')
->dateTime()
->alignCenter()
->sortable()
->toggleable(isToggledHiddenByDefault: true),
Tables\Columns\TextColumn::make('deleted_at')
->dateTime()
->alignCenter()
->sortable()
->toggleable(isToggledHiddenByDefault: true),
])
// ->filters([
// Tables\Filters\TrashedFilter::make(),
// ])
->filters([
Tables\Filters\TrashedFilter::make(),
Filter::make('advanced_filters')
->label('Advanced Filters')
->form([
Select::make('Plant')
->label('Select Plant')
->nullable()
// ->options(function () {
// return Plant::pluck('name', 'id');
// })
->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();
})
->reactive()
->afterStateUpdated(function ($state, callable $set, callable $get) {
$set('electrician_sign', null);
}),
TextInput::make('electrician_sign')
->label('Created By'),
DateTimePicker::make(name: 'created_from')
->label('Created From')
->placeholder(placeholder: 'Select From DateTime')
->reactive()
->native(false),
DateTimePicker::make('created_to')
->label('Created To')
->placeholder(placeholder: 'Select To DateTime')
->reactive()
->native(false),
])
->query(function ($query, array $data) {
// Hide all records initially if no filters are applied
if (empty($data['Plant']) && empty($data['electrician_sign'])) {
return $query->whereRaw('1 = 0');
}
if (!empty($data['Plant'])) {
$query->where('plant_id', $data['Plant']);
}
if (!empty($data['created_from'])) {
$query->where('created_at', '>=', $data['created_from']);
}
if (!empty($data['created_to'])) {
$query->where('created_at', '<=', $data['created_to']);
}
if (!empty($data['electrician_sign'])) {
$query->where('electrician_sign', $data['electrician_sign']);
}
})
->indicateUsing(function (array $data) {
$indicators = [];
if (!empty($data['Plant'])) {
$indicators[] = 'Plant: ' . Plant::where('id', $data['Plant'])->value('name');
}
if (!empty($data['electrician_sign'])) {
$indicators[] = 'Created By: ' . $data['electrician_sign'];
}
if (!empty($data['created_from'])) {
$indicators[] = 'From: ' . $data['created_from'];
}
if (!empty($data['created_to'])) {
$indicators[] = 'To: ' . $data['created_to'];
}
return $indicators;
})
])
->filtersFormMaxHeight('280px')
->actions([
Tables\Actions\ViewAction::make(),
Tables\Actions\EditAction::make(),
])
->bulkActions([
Tables\Actions\BulkActionGroup::make([
Tables\Actions\DeleteBulkAction::make(),
Tables\Actions\ForceDeleteBulkAction::make(),
Tables\Actions\RestoreBulkAction::make(),
]),
])
->headerActions([
ImportAction::make()
->label('Import EB Readings')
->color('warning')
->importer(EbReadingImporter::class)
->visible(function() {
return Filament::auth()->user()->can('view import eb reading');
}),
ExportAction::make()
->label('Export EB Readings')
->color('warning')
->exporter(EbReadingExporter::class)
->visible(function() {
return Filament::auth()->user()->can('view export eb reading');
}),
]);
}
public static function getRelations(): array
{
return [
//
];
}
public static function getPages(): array
{
return [
'index' => Pages\ListEbReadings::route('/'),
'create' => Pages\CreateEbReading::route('/create'),
'view' => Pages\ViewEbReading::route('/{record}'),
'edit' => Pages\EditEbReading::route('/{record}/edit'),
];
}
public static function getEloquentQuery(): Builder
{
return parent::getEloquentQuery()
->withoutGlobalScopes([
SoftDeletingScope::class,
]);
}
}

View File

@@ -0,0 +1,17 @@
<?php
namespace App\Filament\Resources\EbReadingResource\Pages;
use App\Filament\Resources\EbReadingResource;
use Filament\Actions;
use Filament\Resources\Pages\CreateRecord;
class CreateEbReading extends CreateRecord
{
protected static string $resource = EbReadingResource::class;
protected function getRedirectUrl(): string
{
return $this->getResource()::getUrl('create');
}
}

View File

@@ -0,0 +1,22 @@
<?php
namespace App\Filament\Resources\EbReadingResource\Pages;
use App\Filament\Resources\EbReadingResource;
use Filament\Actions;
use Filament\Resources\Pages\EditRecord;
class EditEbReading extends EditRecord
{
protected static string $resource = EbReadingResource::class;
protected function getHeaderActions(): array
{
return [
Actions\ViewAction::make(),
Actions\DeleteAction::make(),
Actions\ForceDeleteAction::make(),
Actions\RestoreAction::make(),
];
}
}

View File

@@ -0,0 +1,19 @@
<?php
namespace App\Filament\Resources\EbReadingResource\Pages;
use App\Filament\Resources\EbReadingResource;
use Filament\Actions;
use Filament\Resources\Pages\ListRecords;
class ListEbReadings extends ListRecords
{
protected static string $resource = EbReadingResource::class;
protected function getHeaderActions(): array
{
return [
Actions\CreateAction::make(),
];
}
}

View File

@@ -0,0 +1,19 @@
<?php
namespace App\Filament\Resources\EbReadingResource\Pages;
use App\Filament\Resources\EbReadingResource;
use Filament\Actions;
use Filament\Resources\Pages\ViewRecord;
class ViewEbReading extends ViewRecord
{
protected static string $resource = EbReadingResource::class;
protected function getHeaderActions(): array
{
return [
Actions\EditAction::make(),
];
}
}

View File

@@ -0,0 +1,514 @@
<?php
namespace App\Filament\Resources;
use App\Filament\Exports\EquipmentMasterExporter;
use App\Filament\Imports\EquipmentMasterImporter;
use App\Filament\Resources\EquipmentMasterResource\Pages;
use App\Filament\Resources\EquipmentMasterResource\RelationManagers;
use App\Models\EquipmentMaster;
use App\Models\Plant;
use Carbon\Carbon;
use Filament\Forms\Components\Actions\Action;
use Filament\Forms;
use Filament\Forms\Form;
use Filament\Resources\Resource;
use Filament\Tables;
use Filament\Tables\Table;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Database\Eloquent\SoftDeletingScope;
use Filament\Facades\Filament;
use Filament\Notifications\Notification;
use Filament\Tables\Actions\ImportAction;
use Filament\Tables\Actions\ExportAction;
use Livewire\Features\SupportFileUploads\TemporaryUploadedFile;
use Storage;
use Illuminate\Validation\Rule;
class EquipmentMasterResource extends Resource
{
protected static ?string $model = EquipmentMaster::class;
protected static ?string $navigationIcon = 'heroicon-o-rectangle-stack';
protected static ?string $navigationGroup = 'Testing Panel';
protected static ?int $navigationSort = 2;
public static function form(Form $form): Form
{
return $form
->schema([
Forms\Components\Select::make('plant_id')
->label('Plant')
->reactive()
->relationship('plant', 'name')
->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(),
Forms\Components\Select::make('machine_id')
//->relationship('machine', 'name')
->label('Work Center')
->reactive()
->options(function (callable $get) {
$plantId = $get('plant_id');
if (empty($plantId)) {
return [];
}
return \App\Models\Machine::where('plant_id', $plantId)->pluck('work_center', 'id');
})
->required(),
Forms\Components\TextInput::make('name')
->label('Name'),
Forms\Components\TextInput::make('description')
->label('Description'),
Forms\Components\TextInput::make('make')
->label('Make'),
Forms\Components\TextInput::make('model')
->label('Model'),
Forms\Components\TextInput::make('equipment_number')
->label('Equipment Number')
->reactive()
->rules(function (callable $get) {
return [
Rule::unique('equipment_masters', 'equipment_number')
->where(function ($query) use ($get) {
return $query->where('plant_id', $get('plant_id'));
})
->ignore($get('id')),
];
})
->afterStateUpdated(function ($state, callable $set) {
if (! $state) {
return;
}
$model = EquipmentMaster::where('equipment_number', $state)->first();
if ($model?->attachment) {
$set('attachment', $model->attachment);
} else {
$set('attachment', null);
}
}),
//->afterStateUpdated(function ($state, callable $set) {
// if (! $state) {
// return;
// }
// $model = EquipmentMaster::where('equipment_number', $state)->first();
// if ($model?->attachment) {
// $set('attachment', $model->attachment);
// } else {
// $set('attachment', null);
// }
// }),
Forms\Components\TextInput::make('instrument_serial_number')
->label('Instrument Serial Number'),
// Forms\Components\DateTimePicker::make('calibrated_on')
// ->label('Calibrated On')
// ->required(),
// Forms\Components\TextInput::make('frequency')
// ->label('Frequency')
// ->required()
// ->numeric()
// ->default(1),
// Forms\Components\DateTimePicker::make('next_calibration_date')
// ->label('Next Calibration Date')
// ->required(),
Forms\Components\DateTimePicker::make('calibrated_on')
->label('Calibrated On')
->required()
->reactive()
->afterStateUpdated(function ($state, callable $set, callable $get) {
$frequency = $get('frequency') ?? '1';
$nextDate = self::calculateNextCalibrationDate($state, $frequency);
$set('next_calibration_date', $nextDate);
}),
// ->afterStateUpdated(function ($state, callable $get, callable $set) {
// $frequency = (int) $get('frequency');
// if ($state && $frequency != 0) {
// $calibratedOn = $state instanceof Carbon ? $state : Carbon::parse($state);
// $nextDate = $calibratedOn->copy()->addDays($frequency);
// $set('next_calibration_date', $nextDate);
// } else {
// $set('next_calibration_date', null);
// }
// }),
Forms\Components\TextInput::make('frequency')
->label('Frequency (days)')
->required()
->numeric()
->minValue(1)
->default(1)
->reactive()
->afterStateUpdated(function ($state, callable $set, callable $get) {
$calibratedOn = $get('calibrated_on');
$nextDate = self::calculateNextCalibrationDate($calibratedOn, $state);
$set('next_calibration_date', $nextDate);
}),
// ->afterStateUpdated(function ($state, callable $get, callable $set) {
// $calibratedOn = $get('calibrated_on');
// $frequency = (int) $state;
// if ($calibratedOn && $frequency !== 0) {
// $calibratedOn = $calibratedOn instanceof Carbon ? $calibratedOn : Carbon::parse($calibratedOn);
// $nextDate = $calibratedOn->copy()->addDays($frequency);
// $set('next_calibration_date', $nextDate);
// }
// else
// {
// $set('next_calibration_date', null);
// }
// }),
Forms\Components\DateTimePicker::make('next_calibration_date')
->label('Next Calibration Date')
->readOnly()
->required(),
Forms\Components\TextInput::make('calibrated_by')
->label('Calibrated By'),
Forms\Components\Textarea::make('calibration_certificate')
->label('Calibration Certificate'),
Forms\Components\FileUpload::make('attachment')
->label('PDF Upload')
->acceptedFileTypes(['application/pdf'])
->storeFiles(false)
->disk('local')
->directory('uploads/temp')
->preserveFilenames()
->reactive(),
// Forms\Components\Actions::make([
// Action::make('uploadNow')
// ->label('Upload PDF Now')
// ->action(function ($get, callable $set) {
// $uploadedFiles = $get('attachment');
// if (is_array($uploadedFiles) && count($uploadedFiles) > 0) {
// $uploaded = reset($uploadedFiles);
// if ($uploaded instanceof TemporaryUploadedFile) {
// $originalName = $uploaded->getClientOriginalName();
// $storedPath = $uploaded->storeAs(
// 'uploads/temp',
// $originalName,
// 'local'
// );
// }
// }
// }),
// ]),
// Forms\Components\Actions::make([
// Action::make('downloadAttachment')
// ->label('Download PDF')
// ->action(function ($get) {
// $uploadedFiles = $get('attachment');
// $equipmentNumber = $get('equipment_number');
// if (!$equipmentNumber) {
// Notification::make()
// ->title('No equipment number entered')
// ->danger()
// ->send();
// return;
// }
// $files = Storage::disk('local')->files('uploads/temp');
// $fileToDownload = null;
// foreach ($files as $file) {
// if (str_contains($file, $equipmentNumber)) {
// $fileToDownload = $file;
// break;
// }
// }
// if (!$fileToDownload) {
// Notification::make()
// ->title('PDF not found for this equipment')
// ->danger()
// ->send();
// return;
// }
// return response()->download(Storage::disk('local')->path($fileToDownload));
// }),
// ]),
Forms\Components\Actions::make([
Action::make('uploadNow')
->label('Upload PDF Now')
// ->action(function ($get, callable $set) {
// $uploadedFiles = $get('attachment');
// if (is_array($uploadedFiles) && count($uploadedFiles) > 0) {
// $uploaded = reset($uploadedFiles);
// if ($uploaded instanceof TemporaryUploadedFile) {
// $originalName = $uploaded->getClientOriginalName();
// $storedPath = $uploaded->storeAs(
// 'uploads/temp',
// $originalName,
// 'local'
// );
// }
// }
// }),
->action(function ($get, callable $set) {
$uploadedFiles = $get('attachment');
if (is_array($uploadedFiles) && count($uploadedFiles) > 0) {
$uploaded = reset($uploadedFiles);
if ($uploaded instanceof TemporaryUploadedFile) {
$originalName = $uploaded->getClientOriginalName();
$storedPath = $uploaded->storeAs(
'uploads/temp',
$originalName,
'local'
);
Notification::make()
->title('PDF uploaded successfully')
->success()
->send();
return;
}
}
else
{
Notification::make()
->title('No file selected to upload')
->warning()
->send();
return;
}
}),
Action::make('downloadAttachment')
->label('Download PDF')
->action(function ($get) {
$equipmentNumber = $get('equipment_number');
if (!$equipmentNumber) {
Notification::make()
->title('No equipment number entered')
->danger()
->send();
return;
}
$files = Storage::disk('local')->files('uploads/temp');
$fileToDownload = null;
foreach ($files as $file) {
if (str_contains($file, $equipmentNumber)) {
$fileToDownload = $file;
break;
}
}
if (!$fileToDownload) {
Notification::make()
->title('PDF not found for this equipment')
->danger()
->send();
return;
}
return response()->download(Storage::disk('local')->path($fileToDownload));
}),
])
->columns(2),
Forms\Components\Hidden::make('created_by')
->label('Created By')
->default(Filament::auth()->user()?->name),
Forms\Components\Hidden::make('updated_by')
->label('Updated By'),
]);
}
public static function table(Table $table): Table
{
return $table
->columns([
Tables\Columns\TextColumn::make('No.')
->label('No.')
->getStateUsing(function ($record, $livewire, $column, $rowLoop) {
$paginator = $livewire->getTableRecords();
$perPage = method_exists($paginator, 'perPage') ? $paginator->perPage() : 10;
$currentPage = method_exists($paginator, 'currentPage') ? $paginator->currentPage() : 1;
return ($currentPage - 1) * $perPage + $rowLoop->iteration;
}),
Tables\Columns\TextColumn::make('plant.name')
->label('Plant')
->alignCenter()
->sortable(),
Tables\Columns\TextColumn::make('machine.work_center')
->label('Work Center')
->alignCenter()
->sortable(),
Tables\Columns\TextColumn::make('name')
->label('Name')
->alignCenter()
->sortable(),
Tables\Columns\TextColumn::make('description')
->label('Description')
->alignCenter()
->sortable(),
Tables\Columns\TextColumn::make('make')
->label('Make')
->alignCenter()
->sortable(),
Tables\Columns\TextColumn::make('model')
->label('Model')
->alignCenter()
->sortable(),
Tables\Columns\TextColumn::make('equipment_number')
->label('Equipment Number')
->alignCenter()
->sortable(),
Tables\Columns\TextColumn::make('instrument_serial_number')
->label('Instrument Serial Number')
->alignCenter()
->sortable(),
Tables\Columns\TextColumn::make('calibrated_on')
->label('Calibrated On')
->alignCenter()
->dateTime()
->sortable(),
Tables\Columns\TextColumn::make('frequency')
->label('Frequency')
->alignCenter()
->sortable(),
Tables\Columns\TextColumn::make('next_calibration_date')
->label('Next Calibration Date')
->alignCenter()
->dateTime()
->sortable(),
Tables\Columns\TextColumn::make('calibrated_by')
->label('Calibrated By')
->alignCenter()
->sortable(),
Tables\Columns\TextColumn::make('calibration_certificate')
->label('Calibration Certificate')
->alignCenter()
->sortable(),
Tables\Columns\TextColumn::make('created_by')
->label('Created Bys')
->alignCenter()
->sortable(),
Tables\Columns\TextColumn::make('updated_by')
->label('Updated By')
->alignCenter()
->sortable(),
Tables\Columns\TextColumn::make('created_at')
->label('Created At')
->dateTime()
->alignCenter()
->sortable()
->toggleable(isToggledHiddenByDefault: true),
Tables\Columns\TextColumn::make('updated_at')
->label('Updated At')
->dateTime()
->alignCenter()
->sortable()
->toggleable(isToggledHiddenByDefault: true),
])
->filters([
Tables\Filters\TrashedFilter::make(),
])
->actions([
Tables\Actions\ViewAction::make(),
Tables\Actions\EditAction::make(),
])
->bulkActions([
Tables\Actions\BulkActionGroup::make([
Tables\Actions\DeleteBulkAction::make(),
Tables\Actions\ForceDeleteBulkAction::make(),
Tables\Actions\RestoreBulkAction::make(),
]),
])
->headerActions([
ImportAction::make()
->label('Import Equipment Masters')
->color('warning')
->importer(EquipmentMasterImporter::class)
->visible(function() {
return Filament::auth()->user()->can('view import equipment master');
}),
ExportAction::make()
->label('Export Equipment Masters')
->color('warning')
->exporter(EquipmentMasterExporter::class)
->visible(function() {
return Filament::auth()->user()->can('view export equipment master');
}),
]);
}
public static function getRelations(): array
{
return [
//
];
}
public static function getPages(): array
{
return [
'index' => Pages\ListEquipmentMasters::route('/'),
'create' => Pages\CreateEquipmentMaster::route('/create'),
'view' => Pages\ViewEquipmentMaster::route('/{record}'),
'edit' => Pages\EditEquipmentMaster::route('/{record}/edit'),
];
}
public static function getEloquentQuery(): Builder
{
return parent::getEloquentQuery()
->withoutGlobalScopes([
SoftDeletingScope::class,
]);
}
protected static function calculateNextCalibrationDate(?string $startDateTime, ?string $durationDays): ?string
{
if (!$startDateTime || !$durationDays) {
return null;
}
try
{
$startDateTimeCarbon = Carbon::parse($startDateTime);
$durationDays = str_replace(',', '.', $durationDays);
if(!is_numeric($durationDays))
{
return null;
}
$nextCalibrationDate = $startDateTimeCarbon->addDays(floatval($durationDays));
return $nextCalibrationDate->format('Y-m-d H:i:s');
}
catch (\Exception $e)
{
return null;
}
}
}

View File

@@ -0,0 +1,17 @@
<?php
namespace App\Filament\Resources\EquipmentMasterResource\Pages;
use App\Filament\Resources\EquipmentMasterResource;
use Filament\Actions;
use Filament\Resources\Pages\CreateRecord;
class CreateEquipmentMaster extends CreateRecord
{
protected static string $resource = EquipmentMasterResource::class;
protected function getRedirectUrl(): string
{
return $this->getResource()::getUrl('create');
}
}

View File

@@ -0,0 +1,22 @@
<?php
namespace App\Filament\Resources\EquipmentMasterResource\Pages;
use App\Filament\Resources\EquipmentMasterResource;
use Filament\Actions;
use Filament\Resources\Pages\EditRecord;
class EditEquipmentMaster extends EditRecord
{
protected static string $resource = EquipmentMasterResource::class;
protected function getHeaderActions(): array
{
return [
Actions\ViewAction::make(),
Actions\DeleteAction::make(),
Actions\ForceDeleteAction::make(),
Actions\RestoreAction::make(),
];
}
}

View File

@@ -0,0 +1,19 @@
<?php
namespace App\Filament\Resources\EquipmentMasterResource\Pages;
use App\Filament\Resources\EquipmentMasterResource;
use Filament\Actions;
use Filament\Resources\Pages\ListRecords;
class ListEquipmentMasters extends ListRecords
{
protected static string $resource = EquipmentMasterResource::class;
protected function getHeaderActions(): array
{
return [
Actions\CreateAction::make(),
];
}
}

View File

@@ -0,0 +1,19 @@
<?php
namespace App\Filament\Resources\EquipmentMasterResource\Pages;
use App\Filament\Resources\EquipmentMasterResource;
use Filament\Actions;
use Filament\Resources\Pages\ViewRecord;
class ViewEquipmentMaster extends ViewRecord
{
protected static string $resource = EquipmentMasterResource::class;
protected function getHeaderActions(): array
{
return [
Actions\EditAction::make(),
];
}
}

View File

@@ -0,0 +1,546 @@
<?php
namespace App\Filament\Resources;
use App\Filament\Exports\GrMasterExporter;
use App\Filament\Imports\GrMasterImporter;
use App\Filament\Resources\GrMasterResource\Pages;
use App\Filament\Resources\GrMasterResource\RelationManagers;
use App\Models\GrMaster;
use App\Models\Item;
use App\Models\Plant;
use Filament\Facades\Filament;
use Filament\Forms;
use Filament\Forms\Form;
use Filament\Resources\Resource;
use Filament\Tables;
use Filament\Tables\Table;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Database\Eloquent\SoftDeletingScope;
use Filament\Notifications\Notification;
use Filament\Forms\Components\Actions\Action;
use Storage;
use Smalot\PdfParser\Parser;
use Livewire\Features\SupportFileUploads\TemporaryUploadedFile;
use Filament\Tables\Actions\ImportAction;
use Filament\Tables\Actions\ExportAction;
use Illuminate\Validation\Rule;
use thiagoalessio\TesseractOCR\TesseractOCR;
use setasign\Fpdi\Fpdi;
use setasign\Fpdi\PdfReader;
use SimpleSoftwareIO\QrCode\Facades\QrCode;
class GrMasterResource extends Resource
{
protected static ?string $model = GrMaster::class;
protected static ?string $navigationIcon = 'heroicon-o-rectangle-stack';
public static function form(Form $form): Form
{
return $form
->schema([
Forms\Components\Select::make('plant_id')
->label('Plant')
->reactive()
->relationship('plant', 'name')
->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(),
Forms\Components\Select::make('item_id')
->label('Item Code')
//->relationship('item', 'id')
->reactive()
->searchable()
->options(function (callable $get) {
$plantId = $get('plant_id');
if (empty($plantId)) {
return [];
}
return Item::where('plant_id', $plantId)->pluck('code', 'id');
})
->required(),
Forms\Components\TextInput::make('gr_number')
->label('GR Number')
->minLength(7)
->required(),
Forms\Components\TextInput::make('serial_number')
->label('Serial Number')
->rule(function (callable $get) {
return Rule::unique('gr_masters', 'serial_number')
->where('plant_id', $get('plant_id'))
->ignore($get('id')); // Ignore current record during updates
}),
Forms\Components\FileUpload::make('attachment')
->label('PDF Upload')
->acceptedFileTypes(['application/pdf'])
->storeFiles(false)
->disk('local')
->directory('uploads/temp')
->preserveFilenames()
->reactive(),
Forms\Components\Actions::make([
Action::make('uploadNow')
->label('Upload PDF Now')
->action(function ($get, callable $set) {
$uploadedFiles = $get('attachment');
if (is_array($uploadedFiles) && count($uploadedFiles) > 0)
{
$uploaded = reset($uploadedFiles);
if ($uploaded instanceof TemporaryUploadedFile) {
$grNumber = $get('gr_number');
$safeName = preg_replace('/[^A-Za-z0-9_\-]/', '_', $grNumber);
// $originalName = $uploaded->getClientOriginalName();
// $path = 'uploads/GRNumber/' . $originalName;
$finalFileName = $safeName . '.pdf';
$finalPath = 'uploads/GRNumber/' . $finalFileName;
if (Storage::disk('local')->exists($finalPath)) {
Notification::make()
->title('Duplicate File')
->body("The file '{$finalFileName}' already exists in uploads/GRNumber.")
->warning()
->send();
return; // Stop here
}
$storedPath = $uploaded->storeAs(
'uploads/GRNumber',
$finalFileName,
'local'
);
// $fullPath = storage_path('app/' . $storedPath);
$fullPath = storage_path('app/private/' . $storedPath);
$parser = new Parser();
//$pdf = $parser->parseContent(file_get_contents($uploaded->getRealPath()));
$pdf = $parser->parseFile($fullPath);
$text = $pdf->getText();
//dd($text);
if (preg_match('/Item code\s*:\s*(\S+)/i', $text, $matches)) {
$item1 = $matches[1];
}
// else if (preg_match('/E CODE\s*:\s*(\S+)/i', $text, $matches)) {
// $item2 = $matches[1];
// dd($item2);
// }
else
{
Notification::make()
->title('Item Code Not Found')
->body('Could not find Item code in uploaded PDF.')
->warning()
->send();
if (Storage::disk('local')->exists($storedPath)) {
Storage::disk('local')->delete($storedPath);
}
return;
}
$processOrder = $get('gr_number');
$itemId = $get('item_id');
$plant = $get('plant_id');
$item = Item::find($itemId);
$plant = Plant::find($plant);
if ($item)
{
$itemCode = $item->code;
}
else
{
$itemCode = null;
Notification::make()
->title('Item Not Found')
->body("Item not found in uploaded pdf.")
->warning()
->send();
if (Storage::disk('local')->exists($storedPath)) {
Storage::disk('local')->delete($storedPath);
}
return;
}
$storedPath = $uploaded->storeAs(
'uploads/GRNumber',
$finalFileName,
'local'
);
if($itemCode == $item1)
{
Notification::make()
->title('Success')
->body("Gr Number '$processOrder' PDF uploaded successfully.")
->success()
->send();
return;
}
else
{
Notification::make()
->title('Item Code not matched')
->body("Item Code: {$item->code} not matched with the uploaded pdf code $item1.")
->danger()
->send();
if (Storage::disk('local')->exists($storedPath)) {
Storage::disk('local')->delete($storedPath);
}
return;
}
}
}
else
{
Notification::make()
->title('No file selected to upload')
->warning()
->send();
return;
}
}),
// Action::make('uploadNow1')
// ->label('Upload OCR')
// ->action(function ($get, callable $set) {
// $uploadedFiles = $get('photo');
// if (is_array($uploadedFiles) && count($uploadedFiles) > 0)
// {
// $uploaded = reset($uploadedFiles);
// if ($uploaded instanceof TemporaryUploadedFile) {
// $grNumber = $get('gr_number');
// $safeName = preg_replace('/[^A-Za-z0-9_\-]/', '_', $grNumber);
// // $originalName = $uploaded->getClientOriginalName();
// // $path = 'uploads/GRNumber/' . $originalName;
// $finalFileName = $safeName . '.jpg';
// $finalPath = 'uploads/OCR/' . $finalFileName;
// // if (Storage::disk('local')->exists($finalPath)) {
// // Notification::make()
// // ->title('Duplicate File')
// // ->body("The file '{$finalFileName}' already exists in uploads/GRNumber.")
// // ->warning()
// // ->send();
// // return; // Stop here
// // }
// $storedPath = $uploaded->storeAs(
// 'uploads/OCR',
// $finalFileName,
// 'local'
// );
// // $storedPath = $uploaded->storeAs('uploads/OCR', $finalFileName, 'local');
// // $fullPath = storage_path('app/' . $storedPath);
// $storedPath = $uploaded->storeAs('uploads/OCR', $finalFileName, 'local');
// $fullPath = storage_path('app/private/' . $storedPath);
// $text = (new TesseractOCR($fullPath))->lang('eng')->run();
// $rawText = $text;
// preg_match_all('/\d+/', $rawText, $matches);
// $serialNumbers = $matches[0];
// $serialNumbers = array_slice($serialNumbers, 0, 4);
// //dd($serialNumbers);
// $processOrder = $get('gr_number');
// $itemId = $get('item_id');
// $plant = $get('plant_id');
// $item = Item::find($itemId);
// $plant = Plant::find($plant);
// $templatePath = storage_path('app/private/uploads/StickerTemplateOcr/multi.pdf');
// $outputPath = storage_path('app/private/uploads/StickerTemplateOcr/multi_filled.pdf');
// $storedPath = $uploaded->storeAs(
// 'uploads/GRNumber',
// $finalFileName,
// 'local'
// );
// $pdf = new Fpdi('P', 'mm', [90, 90]);
// $templateId = $pdf->setSourceFile($templatePath);
// $templatePage = $pdf->importPage(1);
// $pdf->AddPage();
// $pdf->useTemplate($templatePage, 0, 0, 90, 90);
// $pdf->SetFont('Helvetica', '', 10);
// $pdf->SetTextColor(0, 0, 0);
// $slots = [
// ['x' => 5.7, 'y' => 41.9, 'w' => 46.5, 'h' => 3.5], // 1st serial
// ['x' => 50, 'y' => 41.5, 'w' => 46.6, 'h' => 3.9], // 2nd serial
// ['x' => 5.7, 'y' => 60, 'w' => 46.5, 'h' => 3.5], // 3rd serial
// ['x' => 50, 'y' => 60, 'w' => 46.6, 'h' => 3.5], // 4rd serial
// ];
// $qrSlots = [
// ['x' => 17.3, 'y' => 29.2, 'size' => 11.4],
// ['x' => 61.5, 'y' => 29, 'size' => 11.5],
// ['x' => 17.7, 'y' => 46.7, 'size' => 11.4],
// ['x' => 61.7, 'y' => 46.7, 'size' => 11.4],
// ];
// // foreach ($serialNumbers as $i => $serial) {
// // if (isset($slots[$i])) {
// // $pdf->SetFillColor(255, 255, 255); // erase old serial
// // $pdf->Rect($slots[$i]['x'], $slots[$i]['y'], $slots[$i]['w'], $slots[$i]['h'], 'F');
// // $pdf->SetXY($slots[$i]['x'], $slots[$i]['y']);
// // // $pdf->Write(0, $serial);
// // $pdf->Cell($slots[$i]['w'], $slots[$i]['h'], $serial, 0, 0, 'L');
// // }
// // }
// // $pdf->Output('F', $outputPath);
// // return response()->download($outputPath);
// //
// // foreach ($serialNumbers as $i => $serial) {
// // if (!isset($slots[$i]) || !isset($qrSlots[$i])) continue;
// // //Generate QR code PNG temporarily
// // $qrPath = storage_path("app/private/uploads/QR/qr_$serial.png");
// // QrCode::format('png')->size(100)->generate($serial, $qrPath);
// // //Place QR code above serial
// // $pdf->Image($qrPath, $qrSlots[$i]['x'], $qrSlots[$i]['y'], $qrSlots[$i]['size'], $qrSlots[$i]['size']);
// // //Erase old serial
// // $pdf->SetFillColor(255, 255, 255);
// // $pdf->Rect($slots[$i]['x'], $slots[$i]['y'], $slots[$i]['w'], $slots[$i]['h'], 'F');
// // //Write new serial number
// // $pdf->SetXY($slots[$i]['x'], $slots[$i]['y']);
// // $pdf->Cell($slots[$i]['w'], $slots[$i]['h'], $serial, 0, 0, 'L');
// // }
// foreach ($serialNumbers as $i => $serial) {
// if (!isset($slots[$i]) || !isset($qrSlots[$i])) continue;
// // Erase old QR completely (slightly larger)
// $pdf->SetFillColor(255, 255, 255);
// $pdf->Rect($qrSlots[$i]['x']-1, $qrSlots[$i]['y']-1, $qrSlots[$i]['size']+2, $qrSlots[$i]['size']+2, 'F');
// // Generate new QR code
// $qrPath = storage_path("app/private/uploads/QR/qr_$serial.png");
// $qrDir = storage_path('app/private/uploads/QR');
// if (!file_exists($qrDir)) mkdir($qrDir, 0777, true);
// QrCode::format('png')->size(100)->generate($serial, $qrPath);
// // Place QR code
// $pdf->Image($qrPath, $qrSlots[$i]['x'], $qrSlots[$i]['y'], $qrSlots[$i]['size'], $qrSlots[$i]['size']);
// // Erase old serial
// $pdf->SetFillColor(255, 255, 255);
// $pdf->Rect($slots[$i]['x'], $slots[$i]['y'], $slots[$i]['w'], $slots[$i]['h'], 'F');
// // Write new serial
// $pdf->SetXY($slots[$i]['x'], $slots[$i]['y']);
// $pdf->Cell($slots[$i]['w'], $slots[$i]['h'], $serial, 0, 0, 'L');
// }
// // Save the final PDF
// $pdf->Output('F', $outputPath);
// // Download
// return response()->download($outputPath);
// }
// }
// else
// {
// Notification::make()
// ->title('No file selected to upload')
// ->warning()
// ->send();
// return;
// }
// }),
Action::make('downloadAttachment')
->label('Download PDF')
->action(function ($get) {
$equipmentNumber = $get('gr_number');
if (!$equipmentNumber) {
Notification::make()
->title('No GR Number entered')
->danger()
->send();
return;
}
$files = Storage::disk('local')->files('uploads/GRNumber');
$fileToDownload = null;
foreach ($files as $file) {
if (str_contains($file, $equipmentNumber)) {
$fileToDownload = $file;
break;
}
}
if (!$fileToDownload) {
Notification::make()
->title('PDF not found for this process order')
->danger()
->send();
return;
}
return response()->download(Storage::disk('local')->path($fileToDownload));
}),
]),
Forms\Components\Hidden::make('created_by')
->label('Created By')
->default(Filament::auth()->user()?->name),
Forms\Components\Hidden::make('updated_by')
->default(Filament::auth()->user()?->name),
]);
}
public static function table(Table $table): Table
{
return $table
->columns([
Tables\Columns\TextColumn::make('No.')
->label('No.')
->getStateUsing(function ($record, $livewire, $column, $rowLoop) {
$paginator = $livewire->getTableRecords();
$perPage = method_exists($paginator, 'perPage') ? $paginator->perPage() : 10;
$currentPage = method_exists($paginator, 'currentPage') ? $paginator->currentPage() : 1;
return ($currentPage - 1) * $perPage + $rowLoop->iteration;
}),
Tables\Columns\TextColumn::make('plant.name')
->label('Plant')
->alignCenter()
->sortable(),
Tables\Columns\TextColumn::make('item.code')
->label('Item Code')
->searchable()
->alignCenter()
->sortable(),
Tables\Columns\TextColumn::make('gr_number')
->label('GR Number')
->alignCenter()
->searchable()
->sortable(),
Tables\Columns\TextColumn::make('serial_number')
->label('Serial Number')
->alignCenter()
->sortable(),
Tables\Columns\TextColumn::make('created_by')
->label('Created By')
->alignCenter()
->sortable(),
Tables\Columns\TextColumn::make('status')
->label('Status')
->alignCenter()
->sortable(),
Tables\Columns\TextColumn::make('created_at')
->label('Created At')
->alignCenter()
->dateTime()
->sortable()
->toggleable(isToggledHiddenByDefault: true),
Tables\Columns\TextColumn::make('updated_at')
->label('Updated At')
->alignCenter()
->dateTime()
->sortable()
->toggleable(isToggledHiddenByDefault: true),
Tables\Columns\TextColumn::make('deleted_at')
->label('Deleted At')
->alignCenter()
->dateTime()
->sortable()
->toggleable(isToggledHiddenByDefault: true),
])
->filters([
Tables\Filters\TrashedFilter::make(),
])
->actions([
Tables\Actions\ViewAction::make(),
Tables\Actions\EditAction::make(),
])
->bulkActions([
Tables\Actions\BulkActionGroup::make([
Tables\Actions\DeleteBulkAction::make(),
Tables\Actions\ForceDeleteBulkAction::make(),
Tables\Actions\RestoreBulkAction::make(),
]),
])
->headerActions([
ImportAction::make()
->label('Import GR Masters')
->color('warning')
->importer(GrMasterImporter::class)
->visible(function() {
return Filament::auth()->user()->can('view import gr master');
}),
ExportAction::make()
->label('Export GR Masters')
->color('warning')
->exporter(GrMasterExporter::class)
->visible(function() {
return Filament::auth()->user()->can('view export gr master');
}),
]);
}
public static function getRelations(): array
{
return [
//
];
}
public static function getPages(): array
{
return [
'index' => Pages\ListGrMasters::route('/'),
'create' => Pages\CreateGrMaster::route('/create'),
'view' => Pages\ViewGrMaster::route('/{record}'),
'edit' => Pages\EditGrMaster::route('/{record}/edit'),
];
}
public static function getEloquentQuery(): Builder
{
return parent::getEloquentQuery()
->withoutGlobalScopes([
SoftDeletingScope::class,
]);
}
}

View File

@@ -0,0 +1,12 @@
<?php
namespace App\Filament\Resources\GrMasterResource\Pages;
use App\Filament\Resources\GrMasterResource;
use Filament\Actions;
use Filament\Resources\Pages\CreateRecord;
class CreateGrMaster extends CreateRecord
{
protected static string $resource = GrMasterResource::class;
}

View File

@@ -0,0 +1,22 @@
<?php
namespace App\Filament\Resources\GrMasterResource\Pages;
use App\Filament\Resources\GrMasterResource;
use Filament\Actions;
use Filament\Resources\Pages\EditRecord;
class EditGrMaster extends EditRecord
{
protected static string $resource = GrMasterResource::class;
protected function getHeaderActions(): array
{
return [
Actions\ViewAction::make(),
Actions\DeleteAction::make(),
Actions\ForceDeleteAction::make(),
Actions\RestoreAction::make(),
];
}
}

View File

@@ -0,0 +1,23 @@
<?php
namespace App\Filament\Resources\GrMasterResource\Pages;
use App\Filament\Resources\GrMasterResource;
use Filament\Actions;
use Filament\Resources\Pages\ListRecords;
use Filament\Actions\Action;
class ListGrMasters extends ListRecords
{
protected static string $resource = GrMasterResource::class;
protected static string $route = '/ocr-validation';
protected function getHeaderActions(): array
{
return [
Actions\CreateAction::make(),
];
}
}

View File

@@ -0,0 +1,19 @@
<?php
namespace App\Filament\Resources\GrMasterResource\Pages;
use App\Filament\Resources\GrMasterResource;
use Filament\Actions;
use Filament\Resources\Pages\ViewRecord;
class ViewGrMaster extends ViewRecord
{
protected static string $resource = GrMasterResource::class;
protected function getHeaderActions(): array
{
return [
Actions\EditAction::make(),
];
}
}

View File

@@ -0,0 +1,209 @@
<?php
namespace App\Filament\Resources;
use App\Filament\Exports\GuardNameExporter;
use App\Filament\Imports\GuardNameImporter;
use App\Filament\Resources\GuardNameResource\Pages;
use App\Filament\Resources\GuardNameResource\RelationManagers;
use App\Models\GuardName;
use App\Models\Plant;
use Filament\Facades\Filament;
use Filament\Forms;
use Filament\Forms\Form;
use Filament\Forms\Get;
use Filament\Resources\Resource;
use Filament\Tables;
use Filament\Tables\Actions\ExportAction;
use Filament\Tables\Actions\ImportAction;
use Filament\Tables\Table;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Database\Eloquent\SoftDeletingScope;
use Illuminate\Validation\Rule;
class GuardNameResource extends Resource
{
protected static ?string $model = GuardName::class;
protected static ?string $navigationIcon = 'heroicon-o-rectangle-stack';
protected static ?string $navigationGroup = 'Master Entries';
protected static ?int $navigationSort = 14;
public static function form(Form $form): Form
{
return $form
->schema([
Forms\Components\Select::make('plant_id')
->label('Plant')
->relationship('plant', 'name')
->required()
->reactive()
->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();
})
->default(function () {
return optional(GuardName::latest()->first())->plant_id;
})
->disabled(fn (Get $get) => !empty($get('id')))
->afterStateUpdated(function ($state, callable $set, callable $get) {
$plantId = $get('plant_id');
if (!$plantId) {
$set('GnError', 'Please select a plant first.');
return;
}
else
{
$set('GnError', null);
$set('created_by', Filament::auth()->user()?->name);
}
})
->extraAttributes(fn ($get) => [
'class' => $get('GnError') ? 'border-red-500' : '',
])
->hint(fn ($get) => $get('GnError') ? $get('GnError') : null)
->hintColor('danger'),
Forms\Components\TextInput::make('name')
->label('Name')
->required()
->reactive()
->afterStateUpdated(function ($state, callable $set, callable $get) {
$set('created_by', Filament::auth()->user()?->name);
})
->rule(function (callable $get) {
return Rule::unique('guard_names', 'name')
->where('plant_id', $get('plant_id'))
->ignore($get('id'));
}),
Forms\Components\TextInput::make('identification1')
->label('Aadhar Number')
->required()
->reactive()
->afterStateUpdated(function ($state, callable $set, callable $get) {
$set('created_by', Filament::auth()->user()?->name);
}),
Forms\Components\TextInput::make('identification2')
->label('PAN Number')
->reactive()
->afterStateUpdated(function ($state, callable $set, callable $get) {
$set('created_by', Filament::auth()->user()?->name);
}),
Forms\Components\Hidden::make('created_by')
->default(fn () => Filament::auth()->user()?->name)
->required(),
Forms\Components\TextInput::make('id')
->hidden()
->reactive()
->afterStateUpdated(function ($state, callable $set, callable $get) {
$set('created_by', Filament::auth()->user()?->name);
})
->readOnly(),
]);
}
public static function table(Table $table): Table
{
return $table
->columns([
Tables\Columns\TextColumn::make('No.')
->label('No.')
->getStateUsing(function ($record, $livewire, $column, $rowLoop) {
$paginator = $livewire->getTableRecords();
$perPage = method_exists($paginator, 'perPage') ? $paginator->perPage() : 10;
$currentPage = method_exists($paginator, 'currentPage') ? $paginator->currentPage() : 1;
return ($currentPage - 1) * $perPage + $rowLoop->iteration;
}),
// Tables\Columns\TextColumn::make('id')
// ->label('ID')
// ->numeric()
// ->sortable(),
Tables\Columns\TextColumn::make('plant.name')
->label('Plant')
->alignCenter()
->searchable()
->sortable(),
Tables\Columns\TextColumn::make('name')
->label('Guard')
->alignCenter()
->searchable()
->sortable(),
Tables\Columns\TextColumn::make('created_at')
->label('Created At')
->dateTime()
->alignCenter()
->sortable(),
Tables\Columns\TextColumn::make('created_by')
->label('Created By')
->searchable()
->alignCenter(),
Tables\Columns\TextColumn::make('updated_at')
->label('Updated At')
->dateTime()
->alignCenter()
->sortable(),
Tables\Columns\TextColumn::make('deleted_at')
->label('Deleted At')
->dateTime()
->alignCenter()
->sortable()
->toggleable(isToggledHiddenByDefault: true),
])
->filters([
Tables\Filters\TrashedFilter::make(),
])
->actions([
Tables\Actions\ViewAction::make(),
Tables\Actions\EditAction::make(),
])
->bulkActions([
Tables\Actions\BulkActionGroup::make([
Tables\Actions\DeleteBulkAction::make(),
Tables\Actions\ForceDeleteBulkAction::make(),
Tables\Actions\RestoreBulkAction::make(),
]),
])
->headerActions([
ImportAction::make()
->label('Import Guard Names')
->color('warning')
->importer(GuardNameImporter::class)
->visible(function() {
return Filament::auth()->user()->can('view import guard name');
}),
ExportAction::make()
->label('Export Guard Names')
->color('warning')
->exporter(GuardNameExporter::class)
->visible(function() {
return Filament::auth()->user()->can('view export guard name');
}),
]);
}
public static function getRelations(): array
{
return [
//
];
}
public static function getPages(): array
{
return [
'index' => Pages\ListGuardNames::route('/'),
'create' => Pages\CreateGuardName::route('/create'),
'view' => Pages\ViewGuardName::route('/{record}'),
'edit' => Pages\EditGuardName::route('/{record}/edit'),
];
}
public static function getEloquentQuery(): Builder
{
return parent::getEloquentQuery()
->withoutGlobalScopes([
SoftDeletingScope::class,
]);
}
}

View File

@@ -0,0 +1,17 @@
<?php
namespace App\Filament\Resources\GuardNameResource\Pages;
use App\Filament\Resources\GuardNameResource;
use Filament\Actions;
use Filament\Resources\Pages\CreateRecord;
class CreateGuardName extends CreateRecord
{
protected static string $resource = GuardNameResource::class;
protected function getRedirectUrl(): string
{
return $this->getResource()::getUrl('create');
}
}

View File

@@ -0,0 +1,22 @@
<?php
namespace App\Filament\Resources\GuardNameResource\Pages;
use App\Filament\Resources\GuardNameResource;
use Filament\Actions;
use Filament\Resources\Pages\EditRecord;
class EditGuardName extends EditRecord
{
protected static string $resource = GuardNameResource::class;
protected function getHeaderActions(): array
{
return [
Actions\ViewAction::make(),
Actions\DeleteAction::make(),
Actions\ForceDeleteAction::make(),
Actions\RestoreAction::make(),
];
}
}

View File

@@ -0,0 +1,19 @@
<?php
namespace App\Filament\Resources\GuardNameResource\Pages;
use App\Filament\Resources\GuardNameResource;
use Filament\Actions;
use Filament\Resources\Pages\ListRecords;
class ListGuardNames extends ListRecords
{
protected static string $resource = GuardNameResource::class;
protected function getHeaderActions(): array
{
return [
Actions\CreateAction::make(),
];
}
}

View File

@@ -0,0 +1,19 @@
<?php
namespace App\Filament\Resources\GuardNameResource\Pages;
use App\Filament\Resources\GuardNameResource;
use Filament\Actions;
use Filament\Resources\Pages\ViewRecord;
class ViewGuardName extends ViewRecord
{
protected static string $resource = GuardNameResource::class;
protected function getHeaderActions(): array
{
return [
Actions\EditAction::make(),
];
}
}

View File

@@ -0,0 +1,825 @@
<?php
namespace App\Filament\Resources;
use App\Filament\Exports\GuardPatrolEntryExporter;
use App\Filament\Imports\GuardPatrolEntryImporter;
use App\Filament\Resources\GuardPatrolEntryResource\Pages;
use App\Filament\Resources\GuardPatrolEntryResource\RelationManagers;
use App\Models\CheckPointName;
use App\Models\Configuration;
use App\Models\GuardName;
use App\Models\GuardPatrolEntry;
use App\Models\Plant;
use Carbon\Carbon;
use Filament\Facades\Filament;
use Filament\Forms;
use Filament\Forms\Components\DateTimePicker;
use Filament\Forms\Components\FileUpload;
use Filament\Forms\Components\Select;
use Filament\Forms\Components\Tabs\Tab;
use Filament\Forms\Components\TextInput;
use Filament\Forms\Form;
use Filament\Forms\Get;
use Filament\Notifications\Notification;
use Filament\Resources\Resource;
use Filament\Tables;
use Filament\Tables\Actions\ExportAction;
use Filament\Tables\Actions\ImportAction;
use Filament\Tables\Filters\Filter;
use Filament\Tables\Table;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Database\Eloquent\SoftDeletingScope;
use Illuminate\Validation\Rule;
use Maatwebsite\Excel\Facades\Excel;
use Storage;
use Str;
class GuardPatrolEntryResource extends Resource
{
protected static ?string $model = GuardPatrolEntry::class;
protected static ?string $navigationIcon = 'heroicon-o-rectangle-stack';
protected static ?string $navigationGroup = 'Guard';
public static function form(Form $form): Form
{
return $form
->schema([
Forms\Components\Select::make('plant_id')
->label('Plant')
->relationship('plant', 'name')
->required()
->reactive()
->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();
})
->default(function () {
return optional(GuardPatrolEntry::where('created_by', Filament::auth()->user()?->name)->latest()->first())->plant_id;
})
->disabled(fn (Get $get) => !empty($get('id')))
->afterStateUpdated(function ($state, callable $set, callable $get) {
$plantId = $get('plant_id');
if (!$plantId) {
// $set('gPePlantError', 'Please select a plant first.');
$set('gPePlantError', 'Please select a plant first.');
return;
}
else
{
$set('patrol_time', now()->format('Y-m-d H:i:s'));
$set('updated_by', Filament::auth()->user()?->name);
$set('gPePlantError', null);
}
})
->extraAttributes(fn ($get) => [
'class' => $get('gPePlantError') ? 'border-red-500' : '',
])
->hint(fn ($get) => $get('gPePlantError') ? $get('gPePlantError') : null)
->hintColor('danger'),
Forms\Components\Select::make('guard_name_id')
->label('Guard Name')
// ->relationship('guardNames', 'name')
->options(function (callable $get) {
$plantId = $get('plant_id');
if (!$plantId) {
return [];
}
return GuardName::where('plant_id', $plantId)
->pluck('name', 'id')
->toArray();
})
->required()
->reactive()
->default(function () {
return optional(GuardPatrolEntry::where('created_by', Filament::auth()->user()?->name)->latest()->first())->guard_name_id;
})
->disabled(fn (Get $get) => !empty($get('id')))
->afterStateUpdated(function ($state, callable $set, callable $get) {
$guardName = $get('guard_name_id');
if (!$guardName) {
$set('gPeGuardNameError', 'Please select a guard name first.');
return;
}
else
{
$set('patrol_time', now()->format('Y-m-d H:i:s'));
$set('updated_by', Filament::auth()->user()?->name);
$set('gPeGuardNameError', null);
}
})
->extraAttributes(fn ($get) => [
'class' => $get('gPeGuardNameError') ? 'border-red-500' : '',
])
->hint(fn ($get) => $get('gPeGuardNameError') ? $get('gPeGuardNameError') : null)
->hintColor('danger'),
Forms\Components\Hidden::make('check_point_name')//TextInput
->label('Check Point Name')
->reactive()
->afterStateUpdated(function ($state, callable $set, callable $get) {
$set('patrol_time', now()->format('Y-m-d H:i:s'));
$set('updated_by', Filament::auth()->user()?->name);
})
->extraAttributes([
'x-on:keydown.enter.prevent' => '$wire.processCheckPointName()',
]),
Forms\Components\Select::make('check_point_name_id')
->label('Check Point Name')
// ->relationship('checkPointNames', 'name')
->options(function (callable $get) {
$plantId = $get('plant_id');
if (!$plantId) {
return [];
}
return CheckPointName::where('plant_id', $plantId)
->pluck('name', 'id')
->toArray();
})
->required()
->reactive()
// ->default(function () {
// return optional(GuardPatrolEntry::where('created_by', Filament::auth()->user()?->name)->latest()->first())->check_point_name_id;
// })
->disabled(fn (Get $get) => !empty($get('id')))
->afterStateUpdated(function ($state, callable $set, callable $get) {
$checkPointName = $get('check_point_name_id');
if (!$checkPointName) {
$set('check_point_name_id', null);
$set('gPeCheckPointNameError', 'Please select a check point name first.');
return;
}
else
{
$set('patrol_time', now()->format('Y-m-d H:i:s'));
$set('updated_by', Filament::auth()->user()?->name);
$set('gPeCheckPointNameError', null);
}
})
->extraAttributes(fn ($get) => [
'class' => $get('gPeCheckPointNameError') ? 'border-red-500' : '',
])
->hint(fn ($get) => $get('gPeCheckPointNameError') ? $get('gPeCheckPointNameError') : null)
->hintColor('danger')
->rule(function (callable $get) {
return Rule::unique('guard_patrol_entries', 'check_point_name_id')
->where('guard_name_id', $get('guard_name_id'))
->where('patrol_time', now())
->where('plant_id', $get('plant_id'))
->ignore($get('id'));
}),
Forms\Components\TextInput::make('reader_code')
->label('Reader Code')
->hidden(fn (Get $get) => !$get('id'))
->reactive()
->afterStateUpdated(function ($state, callable $set, callable $get) {
if(!$get('id'))
{
$set('patrol_time', now()->format('Y-m-d H:i:s'));
}
$set('updated_by', Filament::auth()->user()?->name);
}),
Forms\Components\DateTimePicker::make('patrol_time')
->label('Patrol Time')
->reactive()
->default(fn () => now())
->readOnly(fn (Get $get) => !$get('id'))
->afterStateUpdated(function ($state, callable $set, callable $get) {
$set('updated_by', Filament::auth()->user()?->name);
})
->required()
->rule(function (callable $get) {
return Rule::unique('guard_patrol_entries', 'patrol_time')
->where('guard_name_id', $get('guard_name_id'))
->where('check_point_name_id', $get('check_point_name_id'))
->where('plant_id', $get('plant_id'))
->ignore($get('id'));
}),
Forms\Components\Hidden::make('created_by')
->default(fn () => Filament::auth()->user()?->name)
->required(),
Forms\Components\Hidden::make('updated_by')
->reactive()
->default(fn () => Filament::auth()->user()?->name)
->required(),
Forms\Components\TextInput::make('id')
->hidden()
->reactive()
->afterStateUpdated(function ($state, callable $set, callable $get) {
$set('updated_by', Filament::auth()->user()?->name);
})
->readOnly(),
]);
}
public static function table(Table $table): Table
{
return $table
->columns([
Tables\Columns\TextColumn::make('No.')
->label('No.')
->getStateUsing(function ($record, $livewire, $column, $rowLoop) {
$paginator = $livewire->getTableRecords();
$perPage = method_exists($paginator, 'perPage') ? $paginator->perPage() : 10;
$currentPage = method_exists($paginator, 'currentPage') ? $paginator->currentPage() : 1;
return ($currentPage - 1) * $perPage + $rowLoop->iteration;
}),
// Tables\Columns\TextColumn::make('id')
// ->label('ID')
// ->numeric()
// ->sortable(),
Tables\Columns\TextColumn::make('plant.name')
->label('Plant')
->alignCenter()
->sortable(),
Tables\Columns\TextColumn::make('guardNames.name') //guard_name_id
->label('Guard Name')
->alignCenter()
->sortable(),
Tables\Columns\TextColumn::make('checkPointNames.name') //check_point_name_id
->label('Check Point Name')
->alignCenter()
->sortable(),
// Tables\Columns\TextColumn::make('reader_code')
// ->label('Reader Code')
// ->alignCenter()
// ->sortable(),
Tables\Columns\TextColumn::make('patrol_time')
->label('Patrol Time')
->dateTime()
->alignCenter()
->sortable(),
Tables\Columns\TextColumn::make('created_at')
->label('Created At')
->dateTime()
->alignCenter()
->sortable(),
Tables\Columns\TextColumn::make('created_by')
->label('Created By')
->alignCenter(),
Tables\Columns\TextColumn::make('updated_at')
->label('Updated At')
->dateTime()
->alignCenter()
->sortable(),
Tables\Columns\TextColumn::make('updated_by')
->label('Updated By')
->alignCenter(),
Tables\Columns\TextColumn::make('deleted_at')
->label('Deleted At')
->dateTime()
->alignCenter()
->sortable()
->toggleable(isToggledHiddenByDefault: true),
])
->filters([
Tables\Filters\TrashedFilter::make(),
Filter::make('advanced_filters')
->label('Advanced Filters')
->form([
Select::make('Plant')
->label('Select Plant')
->nullable()
// ->options(function () {
// return Plant::pluck('name', 'id');
// })
->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();
})
->reactive(),
// ->afterStateUpdated(function ($state, callable $set, callable $get) {
// $set('sticker_master_id', null);
// $set('sap_msg_status', null);
// }),
Select::make('Guard Name')
->label('Select Guard Name')
->options(function (callable $get) {
$plantId = $get('Plant');
if (!$plantId) {
return [];
}
return GuardName::where('plant_id', $plantId)->pluck('name', 'id')->toArray();
})
->reactive(),
Select::make('Check Point Name')
->label('Select Check Point Name')
->options(function (callable $get) {
$plantId = $get('Plant');
if (!$plantId) {
return [];
}
return CheckPointName::where('plant_id', $plantId)->pluck('name', 'id')->toArray();
})
->reactive(),
Select::make('Created By')
->label('Created By')
->placeholder('Select Created By')
->options(function (callable $get) {
$plantId = $get('Plant');
if (!$plantId) {
return [];
}
return GuardPatrolEntry::where('plant_id', $plantId)->orderBy('patrol_time', 'asc')->get()->unique('created_by')->pluck('created_by', 'created_by')->toArray();//, 'id'
})
->reactive(),
DateTimePicker::make(name: 'From Patrol Time')
->label('From Patrol Time')
->beforeOrEqual('To Patrol Time')
->placeholder(placeholder: 'Select From Patrol Time')
->reactive()
->native(false),
DateTimePicker::make('To Patrol Time')
->label('To Patrol Time')
->afterOrEqual('From Patrol Time')
->placeholder(placeholder: 'Select To Patrol Time')
->reactive()
->native(false),
])
->query(function ($query, array $data) {
//Hide all records initially if no filters are applied
if (empty($data['Plant']) && empty($data['Guard Name']) && empty($data['Check Point Name']) && empty($data['Created By']) && empty($data['From Patrol Time']) && empty($data['To Patrol Time'])) {
return $query->whereRaw('1 = 0');
}
if (!empty($data['Plant'])) {
$query->where('plant_id', $data['Plant']);
}
if (!empty($data['Guard Name'])) {
$query->where('guard_name_id', $data['Guard Name']);
}
if (!empty($data['Check Point Name'])) {
$query->where('check_point_name_id', $data['Check Point Name']);
}
if (!empty($data['Created By'])) {
$query->where('created_by', $data['Created By']);
}
if (!empty($data['From Patrol Time'])) {
$query->where('patrol_time', '>=', $data['From Patrol Time']);
}
if (!empty($data['To Patrol Time'])) {
$query->where('patrol_time', '<=', $data['To Patrol Time']);
}
})
->indicateUsing(function (array $data) {
$indicators = [];
if (!empty($data['Plant'])) {
$indicators[] = 'Plant: ' . Plant::where('id', $data['Plant'])->value('name');
}
if (!empty($data['Guard Name'])) {
$indicators[] = 'Guard Name: ' . GuardName::where('plant_id', $data['Plant'])->where('id', $data['Guard Name'])->value('name');
}
if (!empty($data['Check Point Name'])) {
$indicators[] = 'Check Point Name: ' . CheckPointName::where('plant_id', $data['Plant'])->where('id', $data['Check Point Name'])->value('name');
}
if (!empty($data['Created By'])) {
$indicators[] = 'Created By: ' . $data['Created By'];
}
if (!empty($data['From Patrol Time'])) {
$indicators[] = 'From: ' . $data['From Patrol Time'];
}
if (!empty($data['To Patrol Time'])) {
$indicators[] = 'To: ' . $data['To Patrol Time'];
}
return $indicators;
})
])
->filtersFormMaxHeight('280px')
->actions([
Tables\Actions\ViewAction::make(),
Tables\Actions\EditAction::make(),
])
->bulkActions([
Tables\Actions\BulkActionGroup::make([
Tables\Actions\DeleteBulkAction::make(),
Tables\Actions\ForceDeleteBulkAction::make(),
Tables\Actions\RestoreBulkAction::make(),
]),
])
->headerActions([
Tables\Actions\Action::make('guard_patrol_entries')
->label('Import Guard Patrol Entries')
->form([
Select::make('plant_id')
// ->options(Plant::pluck('name', 'id')->toArray())
->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();
})
->label('Select Plant')
->reactive()
->required()
->default(function () {
return optional(GuardPatrolEntry::where('created_by', Filament::auth()->user()?->name)->latest()->first())->plant_id;
})
->afterStateUpdated(function ($state, callable $set, callable $get) {
$plantId = $get('plant_id');
$set('guard_patrol_entry', null);
if (!$plantId) {
$set('gPeSelectPlantError', 'Please select a plant first.');
return;
}
else
{
$set('gPeSelectPlantError', null);
}
})
->extraAttributes(fn ($get) => [
'class' => $get('gPeSelectPlantError') ? 'border-red-500' : '',
])
->hint(fn ($get) => $get('gPeSelectPlantError') ? $get('gPeSelectPlantError') : null)
->hintColor('danger'),
FileUpload::make('guard_patrol_entry')
->label('Import Guard Patrol Entries')
// ->required()
->preserveFilenames() // <- this keeps the original filename
->storeFiles(false)
->reactive()
->required()
->disk('local')
->visible(fn (Get $get) => !empty($get('plant_id')))
->directory('uploads/temp')
// Allow only .xlsx and .xls
->acceptedFileTypes(['application/vnd.openxmlformats-officedocument.spreadsheetml.sheet', 'application/vnd.ms-excel'])
// Optional: Custom error message if needed
->validationMessages([
'mimes' => 'Only .xlsx and .xls files are allowed.',
])
// Server-side validation for extra safety
->rules(['mimes:xlsx,xls']),
])
->action(function (array $data) {
$uploadedFile = $data['guard_patrol_entry'];
$plantId = $data['plant_id'];
$user = Filament::auth()->user()->name;
$disk = Storage::disk('local');
$originalName = $uploadedFile->getClientOriginalName(); // e.g. 3RA0018732.xlsx
$uploadedFileName = pathinfo($originalName, PATHINFO_FILENAME);
// $uploadedFileName = trim(str_replace('.xlsx', '', $originalName));
$folderPath = Configuration::where('c_name', 'GUARD_PATROL_ENTRY_FOLDER_PATH')->where('plant_id', $plantId)->value('c_value');
if(!$folderPath)
{
Notification::make()
->title('Upload Folder Path Not Found!')
->body('Please set the folder path in configuration for Guard Patrol Entry.')
->danger()
->send();
return;
}
$fullFolderPath = "uploads/$folderPath";
// Check if the folder exists, if not, create it
if (!Storage::disk('local')->exists($fullFolderPath))
{
Storage::disk('local')->makeDirectory($fullFolderPath);
}
$path = $uploadedFile->storeAs($fullFolderPath, $originalName, 'local');
$fullPath = Storage::disk('local')->path($path);
if ($fullPath && file_exists($fullPath))
{
$rows = Excel::toArray(null, $fullPath)[0];
if((count($rows) - 1) <= 0)
{
Notification::make()
->title('Invalid Guard Patrol Entry Found')
->body('Uploaded excel sheet is empty or<br>contains no valid data.')
->danger()
->send();
if ($disk->exists($path)) {
$disk->delete($path);
}
return;
}
$invalidRows=[];
$invalidGuardCheckPoints=[];
$unknownGuards=[];
$unknownCheckPoints=[];
$invalidPatrolTimes=[];
$validRowsFound = false;
foreach ($rows as $index => $row)
{
if ($index === 0) continue; // Skip header
$rowNumber = trim($row[0]);
$guardName = trim($row[1]);
$checkPointName = trim($row[2]);
$readerCode = trim($row[3]);
$patrolTime = trim($row[4]);
if (empty($rowNumber)) { continue; }
if (empty($guardName) || empty($checkPointName) || empty($readerCode) || empty($patrolTime)) {
$invalidRows[] = $rowNumber;
continue;
}
else
{
if(Str::length($guardName) < 3 || Str::length($checkPointName) < 3 || Str::length($readerCode) < 3 || Str::length($patrolTime) < 3)
{
$invalidGuardCheckPoints[] = $rowNumber;
continue;
}
else
{
$isValidRow = true;
$guardNames = GuardName::where('plant_id', $plantId)->where('name', $guardName)->first();
if (!$guardNames) {
$unknownGuards[] = $guardName;
$isValidRow = false;
}
$checkPointNames = CheckPointName::where('plant_id', $plantId)->where('name', $checkPointName)->first();
if (!$checkPointNames) {
$unknownCheckPoints[] = $checkPointName;
$isValidRow = false;
}
$formats = ['d-m-Y H:i:s', 'd-m-Y H:i']; //'07-05-2025 08:00' or '07-05-2025 08:00:00'
$patrolDateTime = null;
foreach ($formats as $format) {
try {
$patrolDateTime = Carbon::createFromFormat($format, $patrolTime);
break;
} catch (\Exception $e) {
$invalidPatrolTimes[] = $rowNumber;
$isValidRow = false;
}
}
if (!isset($patrolDateTime)) {
$invalidPatrolTimes[] = $rowNumber;
$isValidRow = false;
//$warnMsg[] = "Invalid 'Patrol DateTime' format. Expected DD-MM-YYYY HH:MM:SS";
}
if ($isValidRow && !$validRowsFound) {
$validRowsFound = true;
}
}
}
}
$uniqueInvalidRows = array_unique($invalidRows);
if (!empty($uniqueInvalidRows)) {
Notification::make()
->title('Invalid Guard Patrol Entry Found')
->body('The following rows contain empty values (Guard name or Check point name or Reader code or Patrol time):<br>' . implode(', ', $uniqueInvalidRows))
->danger()
->send();
if ($disk->exists($path)) {
$disk->delete($path);
}
return;
}
//should contain minimum 13 digit alpha numeric values
$uniqueInvalidGuardCheckPoints = array_unique($invalidGuardCheckPoints);
if (!empty($uniqueInvalidGuardCheckPoints)) {
Notification::make()
->title('Invalid Guard Patrol Entry Found')
->body('The following rows contain invalid values (Guard name or Check point name or Reader code or Patrol time):<br>' . implode(', ', $uniqueInvalidGuardCheckPoints))
->danger()
->send();
if ($disk->exists($path)) {
$disk->delete($path);
}
return;
}
$invalidDataFound = false;
$uniqueUnknownGuards = array_unique($unknownGuards);
if (!empty($uniqueUnknownGuards)) {
Notification::make()
->title('Unknown Guard Names Found')
->body("The following guard names aren't exist in master data:<br>" . implode(', ', $uniqueUnknownGuards))
->danger()
->send();
if ($disk->exists($path)) {
$disk->delete($path);
}
$invalidDataFound = true;
}
$uniqueUnknownCheckPoints = array_unique($unknownCheckPoints);
if (!empty($uniqueUnknownCheckPoints)) {
Notification::make()
->title('Unknown Check Point Names Found')
->body("The following check point names aren't exist in master data:<br>" . implode(', ', $uniqueUnknownCheckPoints))
->danger()
->send();
if ($disk->exists($path)) {
$disk->delete($path);
}
$invalidDataFound = true;
}
$uniqueInvalidPatrolTimes = array_unique($invalidPatrolTimes);
if (!empty($uniqueInvalidPatrolTimes)) {
Notification::make()
->title('Invalid Patrol Time Format Found')
->body("The following rows contains invalid patrol time format (Expected 'DD-MM-YYYY HH:MM:SS'):<br>" . implode(', ', $uniqueInvalidPatrolTimes))
->danger()
->send();
if ($disk->exists($path)) {
$disk->delete($path);
}
$invalidDataFound = true;
}
if ($invalidDataFound) {
return;
}
if (!$validRowsFound) {
Notification::make()
->title('Invalid Guard Patrol Entry Found')
->body('Uploaded excel sheet is empty or<br>contains no valid data.')
->danger()
->send();
if ($disk->exists($path)) {
$disk->delete($path);
}
return;
}
$validCnt = 0;
$dupCnt = 0;
$validRowsFound = false;
foreach ($rows as $index => $row)
{
if ($index === 0) continue; // Skip header
$rowNumber = trim($row[0]);
$guardName = trim($row[1]);
$checkPointName = trim($row[2]);
$readerCode = trim($row[3]);
$patrolTime = trim($row[4]);
if (empty($rowNumber)) { continue; }
if (empty($guardName) || empty($checkPointName) || empty($readerCode) || empty($patrolTime)) {
continue;
}
$isValidRow = true;
$formats = ['d-m-Y H:i:s', 'd-m-Y H:i']; //'07-05-2025 08:00' or '07-05-2025 08:00:00'
$patrolDateTime = null;
foreach ($formats as $format) {
try {
$patrolDateTime = Carbon::createFromFormat($format, $patrolTime);
break;
} catch (\Exception $e) {
$isValidRow = false;
}
}
if (!isset($patrolDateTime)) {
$isValidRow = false;
}
if ($isValidRow) {
$guardNames = GuardName::where('plant_id', $plantId)->where('name', $guardName)->first();
$checkPointNames = CheckPointName::where('plant_id', $plantId)->where('name', $checkPointName)->first();
$guardEntryFound = GuardPatrolEntry::where('plant_id', $plantId)->where('guard_name_id', $guardNames->id)->where('check_point_name_id', $checkPointNames->id)->where('patrol_time', $patrolDateTime->format('Y-m-d H:i:s'))->first();
if ($guardEntryFound) {
//$warnMsg[] = "Duplicate guard patrol entry found";
$dupCnt++;
continue;
}
else
{
$validCnt++;
GuardPatrolEntry::updateOrCreate([
'plant_id' => $plantId,
'guard_name_id' => $guardNames->id,
'check_point_name_id' => $checkPointNames->id,
'patrol_time' => $patrolDateTime->format('Y-m-d H:i:s')
],
[
'reader_code' => $readerCode,
'created_by' => $user,
'updated_by' => $user
]
);
$validRowsFound = true;
}
}
}
if (!$validRowsFound && $dupCnt > 0) {
Notification::make()
->title('Duplicate Guard Patrol Entry Found')
->body("Uploaded excel sheet contains '{$dupCnt}' duplicate entries!<br>Please check the uploaded file and try again.")
->danger()
->send();
if ($disk->exists($path))
{
$disk->delete($path);
}
}
else if ($validRowsFound && $validCnt > 0)
{
//session(['guard_patrol_entry_path' => $fullPath]);
Notification::make()
->title("Success: '{$validCnt}' guard patrol entries imported successfully.")
->success()
->send();
if ($disk->exists($path))
{
$disk->delete($path);
}
}
else
{
Notification::make()
->title('Failed: Something went wrong while uploading guard patrol entries!')
->danger()
->send();
if ($disk->exists($path)) {
$disk->delete($path);
}
}
}
})
->visible(function() {
return Filament::auth()->user()->can('view import guard patrol entries');
}),
ImportAction::make()
->label('Import Guard Patrol Entry')
// ->hidden()
->color('warning')
->importer(GuardPatrolEntryImporter::class)
->visible(function() {
return Filament::auth()->user()->can('view import guard patrol entry');
}),
ExportAction::make()
->label('Export Guard Patrol Entry')
->color('warning')
->exporter(GuardPatrolEntryExporter::class)
->visible(function() {
return Filament::auth()->user()->can('view export guard patrol entry');
}),
]);
}
public static function getRelations(): array
{
return [
//
];
}
public static function getPages(): array
{
return [
'index' => Pages\ListGuardPatrolEntries::route('/'),
'create' => Pages\CreateGuardPatrolEntry::route('/create'),
'view' => Pages\ViewGuardPatrolEntry::route('/{record}'),
'edit' => Pages\EditGuardPatrolEntry::route('/{record}/edit'),
];
}
public static function getEloquentQuery(): Builder
{
return parent::getEloquentQuery()
->withoutGlobalScopes([
SoftDeletingScope::class,
]);
}
}

View File

@@ -0,0 +1,293 @@
<?php
namespace App\Filament\Resources\GuardPatrolEntryResource\Pages;
use App\Filament\Resources\GuardPatrolEntryResource;
use Filament\Actions;
use Filament\Facades\Filament;
use Filament\Notifications\Notification;
use Filament\Resources\Pages\CreateRecord;
class CreateGuardPatrolEntry extends CreateRecord
{
protected static string $resource = GuardPatrolEntryResource::class;
public $plantId;
public $pallet_number;
public $palletNo;
public $pendingPallet;
public $snoCount = 0;
public $pallet_number_locked = false;
public $serial_number;
//protected static string $view = 'filament.resources.pallet-validation-resource.pages.create-pallet-validation';
// protected $listeners = [
// 'updateSnoQuantity' => 'handleUpdateSnoQuantity',
// ];
// public ?array $data = null;
public function processCheckPointName()
{
// $plantId = $this->form->getState()['plant_id'];
// $plantId = trim($plantId) ?? null;
// $pendingPallet = $this->form->getState()['pending_pallet_list'];
// $palletNumber = trim($this->form->getState()['pallet_number'])?? null;
// $palletNumber = trim($palletNumber) ?? null;
// $serialNumber = trim($this->form->getState()['serial_number'])?? null;
// $serialNumber = trim($serialNumber) ?? null;
// $operatorName = Filament::auth()->user()?->name;
// $clickedAt = session('pallet_clicked_time');
// $clickedBy = session('pallet_created_by');
// if(!$palletNumber)
// {
// Notification::make()
// ->title('Pallet number cannot be empty')
// ->danger()
// ->send();
// $this->form->fill([
// 'serial_number' => null,
// 'plant_id' => $plantId,
// 'pallet_number' => $palletNumber,
// 'pending_pallet_list' => $pendingPallet,
// 'Sno_quantity' => 0,
// 'created_by' => $operatorName,
// 'scanned_by' => $operatorName,
// ]);
// return;
// }
// $count = PalletValidation::where('plant_id', $plantId)
// ->where('pallet_number', $palletNumber)
// ->count('pallet_number');
// if(!$serialNumber)
// {
// Notification::make()
// ->title('Serial number cannot be empty')
// ->danger()
// ->send();
// $this->dispatch('loadData', $palletNumber, $plantId);
// $this->form->fill([
// 'serial_number' => null,
// 'plant_id' => $plantId,
// 'pallet_number' => $palletNumber,
// 'pending_pallet_list' => $pendingPallet,
// 'Sno_quantity' => $count,
// 'created_by' => $operatorName,
// 'scanned_by' => $operatorName,
// ]);
// return;
// }
// if(strlen($serialNumber) < 13)
// {
// Notification::make()
// ->title('Serial number should contain minimum 13 digits.')
// ->danger()
// ->send();
// $this->dispatch('loadData', $palletNumber, $plantId);
// $this->form->fill([
// 'serial_number' => null,
// 'plant_id' => $plantId,
// 'pallet_number' => $palletNumber,
// 'pending_pallet_list' => $pendingPallet,
// 'Sno_quantity' => $count,
// 'created_by' => $operatorName,
// 'scanned_by' => $operatorName,
// ]);
// return;
// }
// if (!ctype_alnum($serialNumber))
// {
// Notification::make()
// ->title('Serial number must contain alpha-numeric values only.')
// ->danger()
// ->send();
// $this->dispatch('loadData', $palletNumber, $plantId);
// $this->form->fill([
// 'serial_number' => null,
// 'plant_id' => $plantId,
// 'pallet_number' => $palletNumber,
// 'pending_pallet_list' => $pendingPallet,
// 'Sno_quantity' => $count,
// 'created_by' => $operatorName,
// 'scanned_by' => $operatorName,
// ]);
// return;
// }
// $existInvoiceSno = LocatorInvoiceValidation::where('serial_number', $serialNumber)
// ->where('plant_id', $plantId)
// ->where('scanned_status', '=', 'Scanned')
// ->first();
// $invoiceNumber = $existInvoiceSno?->invoice_number;
// if($existInvoiceSno)
// {
// Notification::make()
// ->title("Scanned serial number '{$serialNumber}' already completed the scanning process and exist in invoice number : {$invoiceNumber}.<br>Scan the new serial number to add!")
// ->danger()
// ->send();
// $this->dispatch('loadData', $palletNumber, $plantId);
// $this->form->fill([
// 'serial_number' => null,
// 'plant_id' => $plantId,
// 'pallet_number' => $palletNumber,
// 'pending_pallet_list' => $pendingPallet,
// 'Sno_quantity' => $count,
// 'created_by' => $operatorName,
// 'scanned_by' => $operatorName,
// ]);
// return;
// }
// $existingRecord = PalletValidation::where('serial_number', $serialNumber)
// ->where('plant_id', $plantId)
// ->first();
// if ($existingRecord)
// {
// if ($existingRecord && $existingRecord->pallet_number == $palletNumber)
// {
// Notification::make()
// ->title("Scanned serial number '{$serialNumber}' is already exists in pallet number '{$palletNumber}'.<br>Scan the new serial number to proceed.")
// ->danger()
// ->send();
// }
// else if ($existingRecord && $existingRecord->pallet_number && $existingRecord->pallet_number != $palletNumber)
// {
// Notification::make()
// ->title("Scanned serial number '{$serialNumber}' already exists in pallet number '{$existingRecord->pallet_number}'.<br>Scan the new serial number to proceed.")
// ->danger()
// ->send();
// }
// else if ($existingRecord && $existingRecord->locator_number)
// {
// Notification::make()
// ->title("Scanned serial number '{$serialNumber}' is already exists in locator number '{$existingRecord->locator_number}'.<br>Scan the new serial number to proceed.")
// ->danger()
// ->send();
// }
// $this->dispatch('loadData', $palletNumber, $plantId);
// $this->form->fill([
// 'serial_number' => null,
// 'plant_id' => $plantId,
// 'pallet_number' => $palletNumber,
// 'pending_pallet_list' => $pendingPallet,
// 'Sno_quantity' => $count,
// 'created_by' => $operatorName,
// 'scanned_by' => $operatorName,
// ]);
// return;
// }
// try
// {
// $existingPallet = PalletValidation::where('plant_id', $plantId)
// ->where('pallet_number', $palletNumber)
// ->first();
// $createdAt = $existingPallet ? $existingPallet->created_at : $clickedAt ?? now();
// $createdBy = $existingPallet ? $existingPallet->created_by : $clickedBy ?? $operatorName;
// $record = PalletValidation::create([
// 'plant_id' => $plantId,
// 'pallet_number' => $palletNumber,
// 'serial_number' => $serialNumber,
// 'created_by' => $createdBy,
// 'scanned_by' => $operatorName,
// 'created_at' => $createdAt,
// 'scanned_at' => now(),
// 'updated_by' => $operatorName,
// ]);
// $count = PalletValidation::where('plant_id', $plantId)
// ->where('pallet_number', $palletNumber)
// ->count('pallet_number');
// if ($record)
// {
// Notification::make()
// ->title("Scanned serial number : '{$serialNumber}' successfully inserted into pallet table!<br>Scan the next new serial number to proceed...")
// ->success()
// ->send();
// $this->snoCount = PalletValidation::where('plant_id', $plantId)
// ->where('pallet_number', $palletNumber)
// ->count();
// $this->form->fill([
// 'plant_id' => $plantId,
// 'pallet_number' => $palletNumber,
// 'serial_number' => null,
// 'pending_pallet_list' => $pendingPallet,
// 'Sno_quantity' => $count,
// 'created_by' => $operatorName,
// 'scanned_by' => $operatorName,
// ]);
// $this->dispatch('loadData', $palletNumber, $plantId);
// }
// else
// {
// Notification::make()
// ->title('Pallet validation not inserted.')
// ->danger()
// ->send();
// $this->dispatch('loadData', $palletNumber, $plantId);
// $this->form->fill([
// 'plant_id' => $plantId,
// 'pallet_number' => $palletNumber,
// 'serial_number' => null,
// 'pending_pallet_list' => $pendingPallet,
// 'Sno_quantity' => $count,
// 'scanned_by' => $operatorName,
// ]);
// return;
// }
// }
// catch (\Exception $e)
// {
// Notification::make()
// ->title('Error: Pallet validation not inserted.')
// ->body("Something went wrong while inserting serial number : '{$serialNumber}' into pallet table!\nScan the new serial number to proceed...")
// ->danger()
// ->send();
// $this->dispatch('loadData', $palletNumber, $plantId);
// $this->form->fill([
// 'plant_id' => $plantId,
// 'pallet_number' => $palletNumber,
// 'serial_number' => null,
// 'pending_pallet_list' => $pendingPallet,
// 'Sno_quantity' => $count,
// 'created_by' => $operatorName,
// 'scanned_by' => $operatorName,
// ]);
// return;
// }
}
protected function getRedirectUrl(): string
{
return $this->getResource()::getUrl('create'); // Stay on Create Page after saving
}
}

View File

@@ -0,0 +1,22 @@
<?php
namespace App\Filament\Resources\GuardPatrolEntryResource\Pages;
use App\Filament\Resources\GuardPatrolEntryResource;
use Filament\Actions;
use Filament\Resources\Pages\EditRecord;
class EditGuardPatrolEntry extends EditRecord
{
protected static string $resource = GuardPatrolEntryResource::class;
protected function getHeaderActions(): array
{
return [
Actions\ViewAction::make(),
Actions\DeleteAction::make(),
Actions\ForceDeleteAction::make(),
Actions\RestoreAction::make(),
];
}
}

View File

@@ -0,0 +1,19 @@
<?php
namespace App\Filament\Resources\GuardPatrolEntryResource\Pages;
use App\Filament\Resources\GuardPatrolEntryResource;
use Filament\Actions;
use Filament\Resources\Pages\ListRecords;
class ListGuardPatrolEntries extends ListRecords
{
protected static string $resource = GuardPatrolEntryResource::class;
protected function getHeaderActions(): array
{
return [
Actions\CreateAction::make(),
];
}
}

View File

@@ -0,0 +1,19 @@
<?php
namespace App\Filament\Resources\GuardPatrolEntryResource\Pages;
use App\Filament\Resources\GuardPatrolEntryResource;
use Filament\Actions;
use Filament\Resources\Pages\ViewRecord;
class ViewGuardPatrolEntry extends ViewRecord
{
protected static string $resource = GuardPatrolEntryResource::class;
protected function getHeaderActions(): array
{
return [
Actions\EditAction::make(),
];
}
}

View File

@@ -0,0 +1,635 @@
<?php
namespace App\Filament\Resources;
use App\Filament\Exports\InvoiceDataValidationExporter;
use App\Filament\Resources\InvoiceDataValidationResource\Pages;
use App\Models\InvoiceDataValidation;
use App\Models\Plant;
use DB;
use Filament\Facades\Filament;
use Filament\Forms;
use Filament\Forms\Components\FileUpload;
use Filament\Forms\Form;
use Filament\Forms\Get;
use Filament\Notifications\Notification;
use Filament\Resources\Resource;
use Filament\Tables;
use Filament\Tables\Actions\ExportAction;
use Filament\Tables\Table;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Database\Eloquent\SoftDeletingScope;
use Illuminate\Support\Facades\Storage;
use Maatwebsite\Excel\Facades\Excel;
class InvoiceDataValidationResource extends Resource
{
protected static ?string $model = InvoiceDataValidation::class;
protected static ?string $navigationIcon = 'heroicon-o-rectangle-stack';
protected static ?string $navigationGroup = 'Invoice Management';
public static function form(Form $form): Form
{
return $form
->schema([
Forms\Components\Select::make('plant_id')
->label('Plant')
->relationship('plant', 'name')
->required(),
Forms\Components\TextInput::make('distribution_channel_desc')
->label('Distribution Channel Description')
->required(),
Forms\Components\TextInput::make('customer_code')
->label('Customer Code')
->required(),
Forms\Components\TextInput::make('document_number')
->label('Document Number')
->required(),
Forms\Components\DatePicker::make('document_date')
->label('Document Date')
->required(),
Forms\Components\TextInput::make('customer_trade_name')
->label('Customer Trade Name')
->required(),
Forms\Components\TextInput::make('customer_location')
->label('Customer Location')
->required(),
Forms\Components\TextInput::make('location')
->label('Location')
->required(),
Forms\Components\Hidden::make('created_by')
->label('Created By')
->default(Filament::auth()->user()?->name),
Forms\Components\Hidden::make('updated_by')
->label('Updated By')
->default(Filament::auth()->user()?->name),
]);
}
public static function table(Table $table): Table
{
return $table
->columns([
Tables\Columns\TextColumn::make('No.')
->label('No.')
->alignCenter()
->getStateUsing(function ($record, $livewire, $column, $rowLoop) {
$paginator = $livewire->getTableRecords();
$perPage = method_exists($paginator, 'perPage') ? $paginator->perPage() : 10;
$currentPage = method_exists($paginator, 'currentPage') ? $paginator->currentPage() : 1;
return ($currentPage - 1) * $perPage + $rowLoop->iteration;
}),
Tables\Columns\TextColumn::make('plant.code')
->label('Plant')
->alignCenter()
->searchable()
->sortable(),
Tables\Columns\TextColumn::make('distribution_channel_desc')
->label('Distribution Channel Description')
->alignCenter()
->searchable()
->sortable(),
Tables\Columns\TextColumn::make('customer_code')
->label('Customer Code')
->alignCenter()
->searchable()
->sortable(),
Tables\Columns\TextColumn::make('document_number')
->label('Document Number')
->alignCenter()
->searchable()
->sortable(),
Tables\Columns\TextColumn::make('document_date')
->label('Document Date')
->alignCenter()
->searchable()
->date()
->sortable(),
Tables\Columns\TextColumn::make('customer_trade_name')
->label('Customer Trade Name')
->alignCenter()
->searchable()
->sortable(),
Tables\Columns\TextColumn::make('customer_location')
->label('Customer Location')
->alignCenter()
->searchable()
->sortable(),
Tables\Columns\TextColumn::make('location')
->label('Location')
->alignCenter()
->searchable()
->sortable(),
Tables\Columns\TextColumn::make('created_at')
->label('Created At')
->alignCenter()
->searchable()
->dateTime()
->sortable(),
// ->toggleable(isToggledHiddenByDefault: true),
Tables\Columns\TextColumn::make('created_by')
->label('Created By')
->alignCenter()
->searchable()
->sortable(),
Tables\Columns\TextColumn::make('updated_at')
->label('Updated At')
->alignCenter()
->searchable()
->dateTime()
->sortable()
->toggleable(isToggledHiddenByDefault: true),
Tables\Columns\TextColumn::make('updated_by')
->label('Updated By')
->alignCenter()
->searchable()
->sortable()
->toggleable(isToggledHiddenByDefault: true),
Tables\Columns\TextColumn::make('deleted_at')
->label('Deleted At')
->alignCenter()
->dateTime()
->sortable()
->toggleable(isToggledHiddenByDefault: true),
])
->filters([
Tables\Filters\TrashedFilter::make(),
])
->actions([
Tables\Actions\ViewAction::make(),
Tables\Actions\EditAction::make(),
])
->bulkActions([
Tables\Actions\BulkActionGroup::make([
Tables\Actions\DeleteBulkAction::make(),
Tables\Actions\ForceDeleteBulkAction::make(),
Tables\Actions\RestoreBulkAction::make(),
]),
])
->headerActions([
Tables\Actions\Action::make('Import Invoice Data')
->label('Import Invoice Data')
->form([
FileUpload::make('invoice_data_file')
->label('Invoice Data File')
// ->required()
->preserveFilenames()
->storeFiles(false)
->reactive()
->required()
->disk('local')
// ->visible(fn (Get $get) => !empty($get('plant_id')))
->directory('uploads/temp'),
])
->action(function (array $data) {
$uploadedFile = $data['invoice_data_file'];
$disk = Storage::disk('local');
$user = Filament::auth()->user();
$operatorName = $user->name;
// Get original filename
$originalName = $uploadedFile->getClientOriginalName(); // e.g. 3RA0018732.xlsx
$originalNameOnly = pathinfo($originalName, PATHINFO_FILENAME);
// Store manually using storeAs to keep original name
$path = $uploadedFile->storeAs('uploads/temp', $originalName, 'local'); // returns relative path
$fullPath = Storage::disk('local')->path($path);
if ($fullPath && file_exists($fullPath)) {
$rows = Excel::toArray(null, $fullPath)[0];
if ((count($rows) - 1) <= 0) {
Notification::make()
->title('Records Not Found')
->body("Import the valid 'Invoice Data' file to proceed..!")
->danger()
->send();
if ($disk->exists($path)) {
$disk->delete($path);
}
return;
}
$invalidPlantCode = [];
$invalidPlaCoFound = [];
$invalidDisChaDesc = [];
$invalidCustomerCode = [];
$invalidDocNo = [];
$invalidDocDate = [];
$invalidCusTradeName = [];
$invalidCusLocation = [];
$invalidUser = [];
$userNotFound = [];
$invalidPlantType = [];
$invalidLocation = [];
$seenPlantDoc = [];
// $duplicateEntries = [];
$duplicateEntriesExcel = [];
foreach ($rows as $index => $row) {
if ($index == 0) {
continue;
} // Skip header
$DisChaDesc = trim($row[3]);
$plantCode = trim($row[4]);
$CustomerCode = trim($row[5]);
$DocNo = trim($row[6]);
$DocDate = trim($row[7]);
$CusTradeName = trim($row[9]);
$CusLocation = trim($row[10]);
$Location = trim($row[36]);
// if (empty($plantCode)) $invalidPlantCode[] = "Row {$index}";
if (empty($DisChaDesc)) {
$invalidDisChaDesc[] = "Row {$index}";
}
if (empty($CustomerCode)) {
$invalidCustomerCode[] = "Row {$index}";
}
if (empty($DocNo)) {
$invalidDocNo[] = "Row {$index}";
}
if (empty($CusTradeName)) {
$invalidCusTradeName[] = "Row {$index}";
}
if (empty($CusLocation)) {
$invalidCusLocation[] = "Row {$index}";
}
if (empty($Location)) {
$invalidLocation[] = "Row {$index}";
}
// if (empty($createdBy)) $invalidUser[] = "Row {$index}";
if (strlen($plantCode) < 4) {
$invalidPlantCode[] = $plantCode;
}
if (! is_numeric($plantCode)) {
$invalidPlantType[] = $plantCode;
} elseif (! Plant::where('code', $plantCode)->first()) {
$invalidPlaCoFound[] = $plantCode;
}
// --- Find Plant by code ---
$plant = Plant::where('code', $plantCode)->first();
// //Duplicate Check in DB ---
// $exists = InvoiceDataValidation::where('plant_id', $plant->id)
// ->where('document_number', $DocNo)
// ->first();
// if ($exists)
// {
// $duplicateEntries[] = "Duplicate record: Document Number '{$DocNo}' already exists for Plant '{$plant->name}'";
// }
// Also check duplicates within the same file ---
$uniqueKey = $plantCode.'_'.$DocNo;
if (in_array($uniqueKey, $seenPlantDoc)) {
$duplicateEntriesExcel[] = "Duplicate in file at Row {$index}: Document Number '{$DocNo}' already exists for Plant '{$plant->name}'";
}
$seenPlantDoc[] = $uniqueKey;
}
if (! empty($invalidCustomerCode) || ! empty($invalidDocNo) || ! empty($invalidDocDate) || ! empty($invalidCusTradeName) || ! empty($invalidCusLocation)) {
$errorMsg = '';
// if (!empty($invalidDisChaDesc)) $errorMsg .= 'Missing Distribution Channel Description in rows: ' . implode(', ', $invalidDisChaDesc) . '<br>';
if (! empty($invalidCustomerCode)) {
$errorMsg .= 'Missing Customer Code in rows: '.implode(', ', $invalidCustomerCode).'<br>';
}
if (! empty($invalidDocNo)) {
$errorMsg .= 'Missing Document Number in rows: '.implode(', ', $invalidDocNo).'<br>';
}
if (! empty($invalidDocDate)) {
$errorMsg .= 'Missing Document Date in rows: '.implode(', ', $invalidDocDate).'<br>';
}
if (! empty($invalidCusTradeName)) {
$errorMsg .= 'Missing Customer Trade Name in rows: '.implode(', ', $invalidCusTradeName).'<br>';
}
if (! empty($invalidCusLocation)) {
$errorMsg .= 'Missing Customer Location in rows: '.implode(', ', $invalidCusLocation).'<br>';
}
if (! empty($invalidLocation)) {
$errorMsg .= 'Missing Location in rows: '.implode(', ', $invalidLocation).'<br>';
}
Notification::make()
->title('Missing Mandatory Fields')
->body($errorMsg)
->danger()
->send();
if ($disk->exists($path)) {
$disk->delete($path);
}
return;
} elseif (! empty($invalidPlantCode)) {
$invalidPlantCode = array_unique($invalidPlantCode);
Notification::make()
->title('Invalid Plant Codes')
->body('The following plant codes should contain minimum 4 digits:<br>'.implode(', ', $invalidPlantCode))
->danger()
->send();
if ($disk->exists($path)) {
$disk->delete($path);
}
return;
} elseif (! empty($invalidPlantType)) {
$invalidPlantType = array_unique($invalidPlantType);
Notification::make()
->title('Invalid Plant Codes')
->body('The following plant codes should contain numeric values:<br>'.implode(', ', $invalidPlantType))
->danger()
->send();
if ($disk->exists($path)) {
$disk->delete($path);
}
return;
} elseif (! empty($invalidPlaCoFound)) {
$invalidPlaCoFound = array_unique($invalidPlaCoFound);
Notification::make()
->title('Invalid Plant Codes')
->body('The following plant codes not found in plants:<br>'.implode(', ', $invalidPlaCoFound))
->danger()
->send();
if ($disk->exists($path)) {
$disk->delete($path);
}
return;
}
// if (!empty($duplicateEntries))
// {
// $duplicateGroupedByPlant = [];
// foreach ($duplicateEntries as $message)
// {
// if (preg_match("/Document Number '([^']+)' already exists for Plant '([^']+)'/", $message, $matches)) {
// $docNo = $matches[1];
// $plantName = trim($matches[2]);
// $duplicateGroupedByPlant[$plantName][] = $docNo;
// }
// }
// $errorMsg = 'Duplicate Document Number found in Database :<br>';
// foreach ($duplicateGroupedByPlant as $plant => $docNumbers) {
// $count = count($docNumbers);
// if ($count > 10)
// {
// $errorMsg .= "Duplicate record(s) for Plant <b>{$plant}</b> : {$count} document numbers already exist in DB<br>";
// }
// else
// {
// $errorMsg .= "Duplicate record(s) for Plant <b>{$plant}</b> : "
// . implode(', ', $docNumbers)
// . " already exist<br>";
// }
// }
// Notification::make()
// //->title('Duplicate Entries in Database')
// ->body($errorMsg)
// ->danger()
// ->send();
// if ($disk->exists($path)) {
// $disk->delete($path);
// }
// return;
// }
if (! empty($duplicateEntriesExcel)) {
$duplicateGroupedByPlantExcel = [];
foreach ($duplicateEntriesExcel as $message) {// "/Document Number '([^']+)' already exist(?:s)?(?: for Plant (.+))?/"
if (preg_match("/Document Number '([^']+)' already exists for Plant '([^']+)'/", $message, $matches)) {
$docNo = $matches[1];
$plantName = $matches[2] ?? 'Unknown';
$duplicateGroupedByPlantExcel[$plantName][] = $docNo;
}
}
$errorMsg = 'Duplicate Document Number found in Uploaded File :<br>';
foreach ($duplicateGroupedByPlantExcel as $plant => $docNumbers) {
// Remove duplicate document numbers for each plant
$uniqueDocNumbers = array_unique($docNumbers);
$count = count($uniqueDocNumbers);
if ($count > 10) {
$errorMsg .= "Duplicate Document Numbers for Plant <b>{$plant}</b> : {$count} Document Numbers already exist in uploaded file<br>";
} else {
$errorMsg .= "Duplicate Document Numbers for Plant <b>{$plant}</b> : '"
.implode(', ', $uniqueDocNumbers)
."' already exist in uploaded file<br>";
}
}
Notification::make()
// ->title('Duplicate Document Number in Uploaded File')
->body($errorMsg)
->danger()
->send();
if ($disk->exists($path)) {
$disk->delete($path);
}
return;
}
// if (!empty($duplicateEntriesExcel))
// {
// //$errorMsg = 'Duplicate Document Number found in the uploaded file:<br>' . implode('<br>', $duplicateEntriesExcel);
// $errorMsg = buildDuplicateMessage($duplicateEntriesExcel, 'Duplicate Document Number found in Uploaded File');
// Notification::make()
// ->title('Duplicate Document Number in Uploaded File')
// ->body($errorMsg)
$successCount = 0;
$failedRecords = [];
DB::beginTransaction();
try {
foreach ($rows as $index => $row) {
if ($index == 0) {
continue;
}
$rowNumber = $index + 1;
try {
$DisChaDesc = trim($row[3]);
$plantCode = trim($row[4]);
$CustomerCode = trim($row[5]);
$DocNo = trim($row[6]);
$DocDate = trim($row[7]);
$CusTradeName = trim($row[9]);
$CusLocation = trim($row[10]);
$Location = trim($row[36]);
if (empty($DocNo)) {
throw new \Exception("Row '{$rowNumber}' Missing QR Code");
}
$plant = Plant::where('code', $plantCode)->first();
if (! $plant) {
throw new \Exception("Invalid plant code : '{$plantCode}'");
}
if (! empty($DocDate)) {
if (preg_match('/^\d{2}[-\/]\d{2}[-\/]\d{4}$/', $DocDate)) {
[$day, $month, $year] = preg_split('/[-\/]/', $DocDate);
$formattedDate = "{$year}-{$month}-{$day}";
} elseif (is_numeric($DocDate)) {
$formattedDate = \PhpOffice\PhpSpreadsheet\Shared\Date::excelToDateTimeObject($DocDate)->format('Y-m-d');
} else {
$formattedDate = date('Y-m-d', strtotime($DocDate));
}
} else {
$formattedDate = null;
}
$record = InvoiceDataValidation::where('plant_id', $plant->id)
->where('document_number', $DocNo)
->first();
$curStat = $record ? 'Updation' : 'Insertion';
if ($record) {
$record->update([
'distribution_channel_desc' => $DisChaDesc,
'customer_code' => $CustomerCode,
'document_date' => $formattedDate,
'customer_trade_name' => $CusTradeName,
'customer_location' => $CusLocation,
'location' => $Location,
'updated_by' => $operatorName,
]);
$inserted = $record;
} else {
// Record does not exist, create with 'created_by'
$inserted = InvoiceDataValidation::create([
'plant_id' => $plant->id,
'document_number' => $DocNo,
'distribution_channel_desc' => $DisChaDesc,
'customer_code' => $CustomerCode,
'document_date' => $formattedDate,
'customer_trade_name' => $CusTradeName,
'customer_location' => $CusLocation,
'location' => $Location,
'created_by' => $operatorName,
]);
}
// $inserted = InvoiceDataValidation::create([
// 'plant_id' => $plant->id,
// 'document_number' => $DocNo,
// 'distribution_channel_desc' => $DisChaDesc,
// 'customer_code' => $CustomerCode,
// 'document_date' => $formattedDate,
// 'customer_trade_name' => $CusTradeName,
// 'customer_location' => $CusLocation,
// 'created_by' => $operatorName
// ]);
if (! $inserted) {
throw new \Exception("{$curStat} failed for Document Number : {$DocNo}");
}
$successCount++;
} catch (\Exception $e) {
$failedRecords[] = [
'row' => $rowNumber,
'document_number' => $DocNo ?? null,
'error' => $e->getMessage(),
];
}
}
DB::commit();
if (count($failedRecords) > 0) {
$failedSummary = collect($failedRecords)
->map(fn ($f) => "Row {$f['row']} ({$f['document_number']}) : {$f['error']}")
->take(5) // limit preview to first 5 errors
->implode("\n");
Notification::make()
->title('Partial Import Warning')
->body("'{$successCount}' records inserted. ".count($failedRecords)." failed.\n\n{$failedSummary}")
->warning()
->send();
} else {
Notification::make()
->title('Import Success')
->body("Successfully imported '{$successCount}' records.")
->success()
->send();
}
} catch (\Exception $e) {
DB::rollBack();
Notification::make()
->title('Import Failed')
->body("No records were inserted. Error : {$e->getMessage()}")
->danger()
->send();
}
}
})
->visible(function () {
return Filament::auth()->user()->can('view import invoice data validation');
}),
ExportAction::make()
->label('Export Invoice Data')
->color('warning')
->exporter(InvoiceDataValidationExporter::class)
->visible(function () {
return Filament::auth()->user()->can('view export invoice data validation');
}),
]);
}
public static function getRelations(): array
{
return [
//
];
}
public static function getPages(): array
{
return [
'index' => Pages\ListInvoiceDataValidations::route('/'),
'create' => Pages\CreateInvoiceDataValidation::route('/create'),
'view' => Pages\ViewInvoiceDataValidation::route('/{record}'),
'edit' => Pages\EditInvoiceDataValidation::route('/{record}/edit'),
];
}
public static function getEloquentQuery(): Builder
{
return parent::getEloquentQuery()
->withoutGlobalScopes([
SoftDeletingScope::class,
]);
}
}

View File

@@ -0,0 +1,12 @@
<?php
namespace App\Filament\Resources\InvoiceDataValidationResource\Pages;
use App\Filament\Resources\InvoiceDataValidationResource;
use Filament\Actions;
use Filament\Resources\Pages\CreateRecord;
class CreateInvoiceDataValidation extends CreateRecord
{
protected static string $resource = InvoiceDataValidationResource::class;
}

View File

@@ -0,0 +1,22 @@
<?php
namespace App\Filament\Resources\InvoiceDataValidationResource\Pages;
use App\Filament\Resources\InvoiceDataValidationResource;
use Filament\Actions;
use Filament\Resources\Pages\EditRecord;
class EditInvoiceDataValidation extends EditRecord
{
protected static string $resource = InvoiceDataValidationResource::class;
protected function getHeaderActions(): array
{
return [
Actions\ViewAction::make(),
Actions\DeleteAction::make(),
Actions\ForceDeleteAction::make(),
Actions\RestoreAction::make(),
];
}
}

View File

@@ -0,0 +1,19 @@
<?php
namespace App\Filament\Resources\InvoiceDataValidationResource\Pages;
use App\Filament\Resources\InvoiceDataValidationResource;
use Filament\Actions;
use Filament\Resources\Pages\ListRecords;
class ListInvoiceDataValidations extends ListRecords
{
protected static string $resource = InvoiceDataValidationResource::class;
protected function getHeaderActions(): array
{
return [
Actions\CreateAction::make(),
];
}
}

View File

@@ -0,0 +1,19 @@
<?php
namespace App\Filament\Resources\InvoiceDataValidationResource\Pages;
use App\Filament\Resources\InvoiceDataValidationResource;
use Filament\Actions;
use Filament\Resources\Pages\ViewRecord;
class ViewInvoiceDataValidation extends ViewRecord
{
protected static string $resource = InvoiceDataValidationResource::class;
protected function getHeaderActions(): array
{
return [
Actions\EditAction::make(),
];
}
}

View File

@@ -0,0 +1,558 @@
<?php
namespace App\Filament\Resources;
use App\Filament\Exports\InvoiceOutValidationExporter;
use App\Filament\Resources\InvoiceOutValidationResource\Pages;
use App\Models\InvoiceOutValidation;
use App\Models\Plant;
use Carbon\Carbon;
use DB;
use Filament\Facades\Filament;
use Filament\Forms;
use Filament\Forms\Components\FileUpload;
use Filament\Forms\Components\Section;
use Filament\Forms\Form;
use Filament\Notifications\Notification;
use Filament\Resources\Resource;
use Filament\Tables;
use Filament\Tables\Actions\ExportAction;
use Filament\Tables\Table;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Database\Eloquent\SoftDeletingScope;
use Maatwebsite\Excel\Facades\Excel;
use PhpOffice\PhpSpreadsheet\Shared\Date as ExcelDate;
use Storage;
class InvoiceOutValidationResource extends Resource
{
protected static ?string $model = InvoiceOutValidation::class;
protected static ?string $navigationIcon = 'heroicon-o-rectangle-stack';
protected static ?string $navigationGroup = 'Invoice Management';
public static function form(Form $form): Form
{
return $form
->schema([
Section::make('')
->schema([
Forms\Components\Select::make('plant_id')
->label('Plant')
->relationship('plant', 'name')
->required(),
Forms\Components\TextInput::make('qr_code')
->label('QR Code'),
Forms\Components\DateTimePicker::make('scanned_at')
->label('Scanned At'),
Forms\Components\TextInput::make('scanned_by')
->label('Scanned By'),
Forms\Components\Hidden::make('created_by')
->label('Created By')
->default(Filament::auth()->user()?->name),
Forms\Components\Hidden::make('updated_by')
->label('Updated By')
->default(Filament::auth()->user()?->name),
])
->columns(4),
]);
}
public static function table(Table $table): Table
{
return $table
->columns([
Tables\Columns\TextColumn::make('No.')
->label('No.')
->alignCenter()
->getStateUsing(function ($record, $livewire, $column, $rowLoop) {
$paginator = $livewire->getTableRecords();
$perPage = method_exists($paginator, 'perPage') ? $paginator->perPage() : 10;
$currentPage = method_exists($paginator, 'currentPage') ? $paginator->currentPage() : 1;
return ($currentPage - 1) * $perPage + $rowLoop->iteration;
}),
Tables\Columns\TextColumn::make('plant.code')
->label('Plant')
->alignCenter()
->searchable()
->sortable(),
Tables\Columns\TextColumn::make('qr_code')
->label('QR Code')
->alignCenter()
->searchable()
->sortable(),
Tables\Columns\TextColumn::make('scanned_at')
->label('Scanned At')
->searchable()
->alignCenter()
->dateTime()
->sortable(),
Tables\Columns\TextColumn::make('scanned_by')
->label('Scanned By')
->searchable()
->alignCenter()
->sortable(),
Tables\Columns\TextColumn::make('created_at')
->label('Created At')
->dateTime()
->searchable()
->alignCenter()
->sortable(),
// ->toggleable(isToggledHiddenByDefault: true),
Tables\Columns\TextColumn::make('created_by')
->label('Created By')
->searchable()
->alignCenter()
->sortable(),
Tables\Columns\TextColumn::make('updated_at')
->label('Updated At')
->dateTime()
->searchable()
->alignCenter()
->sortable()
->toggleable(isToggledHiddenByDefault: true),
Tables\Columns\TextColumn::make('updated_by')
->label('Updated By')
->searchable()
->alignCenter()
->sortable()
->toggleable(isToggledHiddenByDefault: true),
Tables\Columns\TextColumn::make('deleted_at')
->dateTime()
->alignCenter()
->sortable()
->toggleable(isToggledHiddenByDefault: true),
])
->filters([
Tables\Filters\TrashedFilter::make(),
])
->actions([
Tables\Actions\ViewAction::make(),
Tables\Actions\EditAction::make(),
])
->bulkActions([
Tables\Actions\BulkActionGroup::make([
Tables\Actions\DeleteBulkAction::make(),
Tables\Actions\ForceDeleteBulkAction::make(),
Tables\Actions\RestoreBulkAction::make(),
]),
])
->headerActions([
Tables\Actions\Action::make('Import Invoice Out Data')
->label('Import Invoice Out Data')
->form([
FileUpload::make('invoice_data_file')
->label('Invoice Out Data')
// ->required()
->preserveFilenames()
->storeFiles(false)
->reactive()
->required()
->disk('local')
// ->visible(fn (Get $get) => !empty($get('plant_id')))
->directory('uploads/temp'),
])
->action(function (array $data) {
$uploadedFile = $data['invoice_data_file'];
$disk = Storage::disk('local');
$user = Filament::auth()->user();
$operatorName = $user->name;
// Get original filename
$originalName = $uploadedFile->getClientOriginalName(); // e.g. 3RA0018732.xlsx
$originalNameOnly = pathinfo($originalName, PATHINFO_FILENAME);
// Store manually using storeAs to keep original name
$path = $uploadedFile->storeAs('uploads/temp', $originalName, 'local'); // returns relative path
$fullPath = Storage::disk('local')->path($path);
if ($fullPath && file_exists($fullPath)) {
$rows = Excel::toArray(null, $fullPath)[0];
if ((count($rows) - 1) <= 0) {
Notification::make()
->title('Records Not Found')
->body("Import the valid 'Invoice Data' file to proceed..!")
->danger()
->send();
if ($disk->exists($path)) {
$disk->delete($path);
}
return;
}
$invalidPlantCode = [];
$invalidPlaCoFound = [];
$invalidqrCode = [];
$invalidScannedAt = [];
$invalidScannedBy = [];
$invalidUser = [];
$userNotFound = [];
$seenPlantQr = [];
$duplicateQrExcel = [];
// $duplicateQrDb = [];
foreach ($rows as $index => $row) {
if ($index == 0) {
continue;
}
$qrCode = trim($row[1]);
$plantCode = trim($row[2]);
$scannedAt = trim($row[3]);
$scannedby = trim($row[4]);
if (empty($plantCode)) {
$invalidPlantCode[] = "Row {$index}";
}
if (empty($qrCode)) {
$invalidqrCode[] = "Row {$index}";
}
if (empty($scannedAt)) {
$invalidScannedAt[] = "Row {$index}";
}
if (empty($scannedby)) {
$invalidScannedBy[] = "Row {$index}";
}
if (strlen($plantCode) < 4) {
$invalidPlantCode[] = $plantCode;
} elseif (! Plant::where('code', $plantCode)->first()) {
$invalidPlaCoFound[] = $plantCode;
}
$plant = Plant::where('code', $plantCode)->first();
$plantId = $plant->id;
$uniqueKey = $plantCode.'_'.$qrCode;
if (in_array($uniqueKey, $seenPlantQr)) {
$duplicateQrExcel[] = "Duplicate in file at Row {$index}: Document Number '{$qrCode}' already exists for Plant '{$plant->name}'";
}
$seenPlantQr[] = $uniqueKey;
// $existsInDb = InvoiceOutValidation::where('plant_id', $plantId)
// ->where('qr_code', $qrCode)
// ->first();
// if ($existsInDb) {
// $duplicateQrDb[] = "Document Numbers '{$qrCode}' already exists in DB for Plant '{$plant->name}'";
// }
}
if (! empty($invalidqrCode) || ! empty($invalidScannedAt) || ! empty($invalidScannedBy) || ! empty($invalidUser)) {
$errorMsg = '';
if (! empty($invalidqrCode)) {
$errorMsg .= 'Missing Qr code in rows: '.implode(', ', $invalidqrCode).'<br>';
}
if (! empty($invalidScannedAt)) {
$errorMsg .= 'Missing Scanned At in rows: '.implode(', ', $invalidScannedAt).'<br>';
}
if (! empty($invalidScannedBy)) {
$errorMsg .= 'Missing Scanned By in rows: '.implode(', ', $invalidScannedBy).'<br>';
}
Notification::make()
->title('Missing Mandatory Fields')
->body($errorMsg)
->danger()
->send();
if ($disk->exists($path)) {
$disk->delete($path);
}
return;
}
if (! empty($invalidPlantCode)) {
$invalidPlantCode = array_unique($invalidPlantCode);
Notification::make()
->title('Invalid Plant Codes')
->body('The following plant codes should contain minimum 4 digits:<br>'.implode(', ', $invalidPlantCode))
->danger()
->send();
if ($disk->exists($path)) {
$disk->delete($path);
}
return;
}
if (! empty($invalidPlaCoFound)) {
$invalidPlaCoFound = array_unique($invalidPlaCoFound);
Notification::make()
->title('Invalid Plant Codes')
->body('The following plant codes not found in plants:<br>'.implode(', ', $invalidPlaCoFound))
->danger()
->send();
if ($disk->exists($path)) {
$disk->delete($path);
}
return;
}
if (! empty($userNotFound)) {
$userNotFound = array_unique($userNotFound);
Notification::make()
->title('Invalid User')
->body('The following user not found:<br>'.implode(', ', $userNotFound))
->danger()
->send();
if ($disk->exists($path)) {
$disk->delete($path);
}
return;
}
if (! empty($duplicateQrExcel)) {
$duplicateGroupedByPlantQr = [];
foreach ($duplicateQrExcel as $message) {// "/Document Numbers '([^']+)' already exists for Plant Code (\S+)/"
if (preg_match("/Document Number '([^']+)' already exists for Plant '([^']+)'/", $message, $matches)) {
$qrCode = $matches[1];
$plantCode = $matches[2];
$duplicateGroupedByPlantQr[$plantCode][] = $qrCode;
}
}
$errorMsg = 'Duplicate Document Number found in Uploaded File :<br>';
foreach ($duplicateGroupedByPlantQr as $plantCode => $qrCodes) {
$uniqueQrCodes = array_unique($qrCodes);
$count = count($uniqueQrCodes);
if ($count > 10) {
$errorMsg .= "Duplicate Document Numbers for Plant <b>{$plantCode}</b> : {$count} Document Numbers already exist in uploaded file<br>";
} else {
$errorMsg .= "Duplicate Document Numbers for Plant <b>{$plantCode}</b> : '"
.implode(', ', $uniqueQrCodes)
."' already exist in uploaded file<br>";
}
}
Notification::make()
// ->title('Duplicate Document Number in Uploaded File')
->body($errorMsg)
->danger()
->send();
if ($disk->exists($path)) {
$disk->delete($path);
}
return;
}
// if (!empty($duplicateQrDb)) {
// $duplicateGroupedByPlantDb = [];
// foreach ($duplicateQrDb as $message) {
// if (preg_match("/Document Numbers '([^']+)' already exists in DB for Plant '([^']+)'/", $message, $matches)) {
// $qrCode = $matches[1];
// $plantCode = $matches[2];
// $duplicateGroupedByPlantDb[$plantCode][] = $qrCode;
// }
// }
// $errorMsg = 'Duplicate Document Numbers found in Database:<br>';
// foreach ($duplicateGroupedByPlantDb as $plantCode => $qrCodes) {
// $uniqueQrCodes = array_unique($qrCodes);
// $count = count($uniqueQrCodes);
// if ($count > 10) {
// $errorMsg .= "Duplicate Document Numbers for Plant <b>{$plantCode}</b>: {$count} Document Numbers already exist in DB<br>";
// } else {
// $errorMsg .= "Duplicate Document Numbers for Plant <b>{$plantCode}</b>: "
// . implode(', ', $uniqueQrCodes)
// . " already exist in DB<br>";
// }
// }
// Notification::make()
// // ->title('Duplicate Document Numbers in Database')
// ->body($errorMsg)
// ->danger()
// ->send();
// if ($disk->exists($path)) {
// $disk->delete($path);
// }
// return;
// }
$successCount = 0;
$failedRecords = [];
DB::beginTransaction();
try {
foreach ($rows as $index => $row) {
if ($index == 0) {
continue;
}
$rowNumber = $index + 1;
try {
$qrcode = trim($row[1]);
$plantCode = trim($row[2]);
$scannedAt = trim($row[3]);
$scannedBy = trim($row[4]);
if (empty($qrcode)) {
throw new \Exception("Row '{$rowNumber}' Missing QR Code");
}
$plant = Plant::where('code', $plantCode)->first();
if (! $plant) {
throw new \Exception("Invalid plant code : '{$plantCode}'");
}
$formattedDate = null;
if (! empty($scannedAt)) {
try {
// $formattedDate = Carbon::createFromFormat('d-m-Y H:i:s', $scannedAt)
// ->format('Y-m-d H:i:s');
if (is_numeric($scannedAt)) {
$formattedDate = ExcelDate::excelToDateTimeObject($scannedAt)
->format('Y-m-d H:i:s');
} else {
// Or handle as manual string date (d-m-Y H:i:s)
$formattedDate = Carbon::createFromFormat('d-m-Y H:i:s', $scannedAt)
->format('Y-m-d H:i:s');
}
} catch (\Exception $e) {
throw new \Exception("Invalid date format : '{$scannedAt}'");
}
}
$record = InvoiceOutValidation::where('plant_id', $plant->id)
->where('qr_code', $qrcode)
->first();
$curStat = $record ? 'Updation' : 'Insertion';
if ($record) {
$record->update([
'scanned_at' => $formattedDate,
'scanned_by' => $scannedBy,
'updated_by' => $operatorName,
]);
$inserted = $record;
} else {
// Record does not exist, create with 'created_by'
$inserted = InvoiceOutValidation::create([
'plant_id' => $plant->id,
'qr_code' => $qrcode,
'scanned_at' => $formattedDate,
'scanned_by' => $scannedBy,
'created_by' => $operatorName,
]);
}
// $inserted = InvoiceOutValidation::create([
// 'plant_id' => $plant->id,
// 'qr_code' => $qrcode,
// 'scanned_at' => $formattedDate,
// 'scanned_by' => $scannedBy,
// 'created_by' => $operatorName
// ]);
if (! $inserted) {
throw new \Exception("{$curStat} failed for QR : {$qrcode}");
}
$successCount++;
} catch (\Exception $e) {
$failedRecords[] = [
'row' => $rowNumber,
'qrcode' => $qrcode ?? null,
'error' => $e->getMessage(),
];
}
}
DB::commit();
if (count($failedRecords) > 0) {
$failedSummary = collect($failedRecords)
->map(fn ($f) => "Row {$f['row']} ({$f['qrcode']}) : {$f['error']}")
->take(5) // limit preview to first 5 errors
->implode("\n");
Notification::make()
->title('Partial Import Warning')
->body("'{$successCount}' records inserted. ".count($failedRecords)." failed.\n\n{$failedSummary}")
->warning()
->send();
} else {
Notification::make()
->title('Import Success')
->body("Successfully imported '{$successCount}' records.")
->success()
->send();
}
} catch (\Exception $e) {
DB::rollBack();
Notification::make()
->title('Import Failed')
->body("No records were inserted. Error : {$e->getMessage()}")
->danger()
->send();
}
}
})
->visible(function () {
return Filament::auth()->user()->can('view import invoice out validation');
}),
ExportAction::make()
->label('Export Invoice Out Data')
->color('warning')
->exporter(InvoiceOutValidationExporter::class)
->visible(function () {
return Filament::auth()->user()->can('view export invoice out validation');
}),
]);
}
public static function getRelations(): array
{
return [
//
];
}
public static function getPages(): array
{
return [
'index' => Pages\ListInvoiceOutValidations::route('/'),
'create' => Pages\CreateInvoiceOutValidation::route('/create'),
'view' => Pages\ViewInvoiceOutValidation::route('/{record}'),
'edit' => Pages\EditInvoiceOutValidation::route('/{record}/edit'),
];
}
public static function getEloquentQuery(): Builder
{
return parent::getEloquentQuery()
->withoutGlobalScopes([
SoftDeletingScope::class,
]);
}
}

View File

@@ -0,0 +1,12 @@
<?php
namespace App\Filament\Resources\InvoiceOutValidationResource\Pages;
use App\Filament\Resources\InvoiceOutValidationResource;
use Filament\Actions;
use Filament\Resources\Pages\CreateRecord;
class CreateInvoiceOutValidation extends CreateRecord
{
protected static string $resource = InvoiceOutValidationResource::class;
}

View File

@@ -0,0 +1,22 @@
<?php
namespace App\Filament\Resources\InvoiceOutValidationResource\Pages;
use App\Filament\Resources\InvoiceOutValidationResource;
use Filament\Actions;
use Filament\Resources\Pages\EditRecord;
class EditInvoiceOutValidation extends EditRecord
{
protected static string $resource = InvoiceOutValidationResource::class;
protected function getHeaderActions(): array
{
return [
Actions\ViewAction::make(),
Actions\DeleteAction::make(),
Actions\ForceDeleteAction::make(),
Actions\RestoreAction::make(),
];
}
}

View File

@@ -0,0 +1,19 @@
<?php
namespace App\Filament\Resources\InvoiceOutValidationResource\Pages;
use App\Filament\Resources\InvoiceOutValidationResource;
use Filament\Actions;
use Filament\Resources\Pages\ListRecords;
class ListInvoiceOutValidations extends ListRecords
{
protected static string $resource = InvoiceOutValidationResource::class;
protected function getHeaderActions(): array
{
return [
Actions\CreateAction::make(),
];
}
}

View File

@@ -0,0 +1,19 @@
<?php
namespace App\Filament\Resources\InvoiceOutValidationResource\Pages;
use App\Filament\Resources\InvoiceOutValidationResource;
use Filament\Actions;
use Filament\Resources\Pages\ViewRecord;
class ViewInvoiceOutValidation extends ViewRecord
{
protected static string $resource = InvoiceOutValidationResource::class;
protected function getHeaderActions(): array
{
return [
Actions\EditAction::make(),
];
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,22 @@
<?php
namespace App\Filament\Resources\InvoiceValidationResource\Pages;
use App\Filament\Resources\InvoiceValidationResource;
use Filament\Actions;
use Filament\Resources\Pages\EditRecord;
class EditInvoiceValidation extends EditRecord
{
protected static string $resource = InvoiceValidationResource::class;
protected function getHeaderActions(): array
{
return [
Actions\ViewAction::make(),
Actions\DeleteAction::make(),
Actions\ForceDeleteAction::make(),
Actions\RestoreAction::make(),
];
}
}

View File

@@ -0,0 +1,29 @@
<?php
namespace App\Filament\Resources\InvoiceValidationResource\Pages;
use App\Filament\Resources\InvoiceValidationResource;
use Filament\Actions;
use Filament\Actions\Action;
use Filament\Forms\Components\FileUpload;
use Filament\Resources\Pages\ListRecords;
class ListInvoiceValidations extends ListRecords
{
protected static string $resource = InvoiceValidationResource::class;
protected function getHeaderActions(): array
{
return [
Actions\CreateAction::make(),
];
}
// //to hide the data from the table
// protected function getTableQuery(): \Illuminate\Database\Eloquent\Builder
// {
// return static::getResource()::getEloquentQuery()->whereRaw('1 = 0');
// }
}

View File

@@ -0,0 +1,19 @@
<?php
namespace App\Filament\Resources\InvoiceValidationResource\Pages;
use App\Filament\Resources\InvoiceValidationResource;
use Filament\Actions;
use Filament\Resources\Pages\ViewRecord;
class ViewInvoiceValidation extends ViewRecord
{
protected static string $resource = InvoiceValidationResource::class;
protected function getHeaderActions(): array
{
return [
Actions\EditAction::make(),
];
}
}

View File

@@ -0,0 +1,657 @@
<?php
namespace App\Filament\Resources;
use App\Filament\Exports\ItemExporter;
use App\Filament\Imports\ItemImporter;
use App\Filament\Resources\ItemResource\Pages;
use App\Models\InvoiceValidation;
use App\Models\Item;
use App\Models\Plant;
use App\Models\StickerMaster;
use Filament\Actions\Exports\Enums\ExportFormat;
use Filament\Facades\Filament;
use Filament\Forms;
use Filament\Forms\Components\DateTimePicker;
use Filament\Forms\Components\FileUpload;
use Filament\Forms\Components\Section;
use Filament\Forms\Components\Select;
use Filament\Forms\Components\TextInput;
use Filament\Forms\Form;
use Filament\Forms\Get;
use Filament\Notifications\Notification;
use Filament\Resources\Resource;
use Filament\Tables;
use Filament\Tables\Actions\ExportAction;
use Filament\Tables\Actions\ImportAction;
use Filament\Tables\Filters\Filter;
use Filament\Tables\Table;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Database\Eloquent\SoftDeletingScope;
use Illuminate\Validation\Rule;
use Maatwebsite\Excel\Facades\Excel;
class ItemResource extends Resource
{
protected static ?string $model = Item::class;
protected static ?string $navigationIcon = 'heroicon-o-rectangle-stack';
protected static ?string $navigationGroup = 'Master Entries';
protected static ?int $navigationSort = 6;
public static function form(Form $form): Form
{
return $form
->schema([
Section::make('')
->schema([
Forms\Components\Select::make('plant_id')
->relationship('plant', 'name')
->required()
// ->preload()
// ->nullable(),
->reactive()
->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();
})
->default(function () {
return optional(Item::latest()->first())->plant_id;
})
->disabled(fn (Get $get) => ! empty($get('id')))
// ->afterStateUpdated(fn ($set) => $set('block_id', null) & $set('name', null) & $set('start_time', null) & $set('duration', null) & $set('end_time', null))
->afterStateUpdated(function ($state, callable $set, callable $get) {
$plantId = $get('plant_id');
// Ensure `linestop_id` is not cleared
if (! $plantId) {
$set('iPlantError', 'Please select a plant first.');
return;
} else {
$set('iPlantError', null);
}
})
->extraAttributes(fn ($get) => [
'class' => $get('iPlantError') ? 'border-red-500' : '',
])
->hint(fn ($get) => $get('iPlantError') ? $get('iPlantError') : null)
->hintColor('danger'),
Forms\Components\TextInput::make('category')
->label('Category')
->placeholder('Scan the Category'),
Forms\Components\TextInput::make('code')
->required()
->placeholder('Scan the valid code')
->autofocus(true)
// ->unique(ignoreRecord: true)
->alphaNum()
->minLength(6)
// ->autocapitalize('characters')
->reactive()
->disabled(fn (Get $get) => ! empty($get('id')))
->afterStateUpdated(function ($state, callable $set, callable $get) {
$code = $get('code');
// Ensure `linestop_id` is not cleared
if (! $code) {
$set('iCodeError', 'Scan the valid code.');
return;
} else {
if (strlen($code) < 6) {
$set('iCodeError', 'Item code must be at least 6 digits.');
return;
} elseif (! preg_match('/^[a-zA-Z0-9]{6,}$/', $code)) {
$set('code', null);
$set('iCodeError', 'Item code must contain only alpha-numeric characters.');
return;
}
$set('iCodeError', null);
}
})
->extraAttributes(fn ($get) => [
'class' => $get('iCodeError') ? 'border-red-500' : '',
])
->hint(fn ($get) => $get('iCodeError') ? $get('iCodeError') : null)
->hintColor('danger')
->rule(function (callable $get) {
return Rule::unique('items', 'code')
->where('plant_id', $get('plant_id'))
->ignore($get('id')); // Ignore current record during updates
}),
Forms\Components\TextInput::make('hourly_quantity')
->required()
->label('Hourly Quantity')
->placeholder('Scan the valid quantity')
->integer()
->default(1)
->minValue(1)
->reactive()
->afterStateUpdated(function ($state, callable $set, callable $get) {
$hourQuan = $get('hourly_quantity');
// Ensure `linestop_id` is not cleared
if (! $hourQuan) {
$set('iHourQuanError', 'Scan the valid hourly quantity.');
return;
} else {
if (! preg_match('/^[0-9]{1,}$/', $hourQuan)) {
$set('hourly_quantity', null);
$set('iHourQuanError', 'Quantity must be integer value.');
return;
}
$set('iHourQuanError', null);
}
})
->extraAttributes(fn ($get) => [
'class' => $get('iHourQuanError') ? 'border-red-500' : '',
])
->hint(fn ($get) => $get('iHourQuanError') ? $get('iHourQuanError') : null)
->hintColor('danger'),
Forms\Components\TextInput::make('uom')
->required()
->label('Unit of Measure')
->placeholder('Scan the valid uom'),
Forms\Components\TextInput::make('description')
->placeholder('Scan the valid description')
->required()
->minLength(5)
->columnSpan(['default' => 1, 'sm' => 1]),
// ->columnSpanFull(),
Forms\Components\TextInput::make('id')
->hidden()
->readOnly(),
])
->columns(3),
]);
}
public static function table(Table $table): Table
{
return $table
->columns([
// Tables\Columns\TextColumn::make('id')
// ->label('ID')
// ->numeric()
// ->sortable(),
Tables\Columns\TextColumn::make('No.')
->label('No.')
// ->getStateUsing(fn ($record, $livewire, $column, $rowLoop) => $rowLoop->iteration),
->getStateUsing(function ($record, $livewire, $column, $rowLoop) {
$paginator = $livewire->getTableRecords();
$perPage = method_exists($paginator, 'perPage') ? $paginator->perPage() : 10;
$currentPage = method_exists($paginator, 'currentPage') ? $paginator->currentPage() : 1;
return ($currentPage - 1) * $perPage + $rowLoop->iteration;
}),
Tables\Columns\TextColumn::make('plant.name')
->label('Plant')
->alignCenter()
->sortable()
->searchable(),
Tables\Columns\TextColumn::make('category')
->label('Category')
->alignCenter()
->sortable()
->searchable(),
Tables\Columns\TextColumn::make('code')
->label('Item Code')
->alignCenter()
->sortable()
->searchable(),
Tables\Columns\TextColumn::make('description')
->label('Description')
->alignCenter()
->sortable()
->searchable(),
Tables\Columns\TextColumn::make('hourly_quantity')
->label('Hourly Quantity')
->numeric()
->alignCenter()
->sortable(),
Tables\Columns\TextColumn::make('uom')
->label('Unit of Measure')
->alignCenter()
->sortable(),
Tables\Columns\TextColumn::make('created_at')
->label('Created At')
->dateTime()
->alignCenter()
->sortable(),
Tables\Columns\TextColumn::make('updated_at')
->label('Updated At')
->dateTime()
->alignCenter()
->sortable()
->toggleable(isToggledHiddenByDefault: true),
Tables\Columns\TextColumn::make('deleted_at')
->label('Deleted At')
->dateTime()
->alignCenter()
->sortable()
->toggleable(isToggledHiddenByDefault: true),
])
->filters([
Tables\Filters\TrashedFilter::make(),
Filter::make('advanced_filters')
->label('Advanced Filters')
->form([
Select::make('Plant')
->label('Select Plant')
->nullable()
->options(function (callable $get) {
$userHas = Filament::auth()->user()->plant_id;
return ($userHas && strlen($userHas) > 0) ? Plant::where('id', $userHas)->orderBy('code')->pluck('name', 'id')->toArray() : Plant::orderBy('code')->pluck('name', 'id')->toArray();
})
->reactive()
->afterStateUpdated(function ($state, callable $set, callable $get): void {
$set('code', null);
$set('operator_id', null);
}),
Select::make('code')
->label('Search by Item Code')
->nullable()
// ->options(function (callable $get) {
// $plantId = $get('Plant');
// return $plantId
// ? Item::where('plant_id', $plantId)->pluck('code', 'id')
// : Item::pluck('code', 'id');
// })
->options(function (callable $get) {
$plantId = $get('Plant');
return $plantId ? Item::where('plant_id', $plantId)->pluck('code', 'id') : [];
})
->searchable()
->reactive(),
TextInput::make('description')
->label('Search by Description')
->placeholder(placeholder: 'Enter Description'),
TextInput::make('category')
->label('Search by Category')
->placeholder(placeholder: 'Enter Category'),
TextInput::make('uom')
->label('Search by UOM')
->placeholder(placeholder: 'Enter UOM'),
DateTimePicker::make(name: 'created_from')
->label('Created From')
->placeholder(placeholder: 'Select From DateTime')
->reactive()
->native(false),
DateTimePicker::make('created_to')
->label('Created To')
->placeholder(placeholder: 'Select To DateTime')
->reactive()
->native(false),
])
->query(function ($query, array $data) {
// Hide all records initially if no filters are applied
if (
empty($data['Plant']) &&
empty($data['code']) &&
empty($data['description']) &&
empty($data['uom']) &&
empty($data['category']) &&
empty($data['created_from']) &&
empty($data['created_to'])
) {
return $query->whereRaw('1 = 0');
}
if (! empty($data['Plant'])) { // $plant = $data['Plant'] ?? null
$query->where('plant_id', $data['Plant']);
}
if (! empty($data['code'])) {
$query->where('id', $data['code']);
}
if (! empty($data['description'])) {
$query->where('description', '%'.$data['description'].'%');
}
if (! empty($data['uom'])) {
$query->where('uom', 'like', '%'.$data['uom'].'%');
}
if (! empty($data['category'])) {
$query->where('category', '%'.$data['category'].'%');
}
if (! empty($data['created_from'])) {
$query->where('created_at', '>=', $data['created_from']);
}
if (! empty($data['created_to'])) {
$query->where('created_at', '<=', $data['created_to']);
}
})
->indicateUsing(function (array $data) {
$indicators = [];
if (! empty($data['Plant'])) {
$indicators[] = 'Plant: '.Plant::where('id', $data['Plant'])->value('name');
}
if (! empty($data['code'])) {
$indicators[] = 'Item Code: '.Item::where('id', $data['code'])->value('code');
}
if (! empty($data['description'])) {
$indicators[] = 'Description: '.$data['description'];
}
if (! empty($data['uom'])) {
$indicators[] = 'UOM: '.$data['uom'];
}
if (! empty($data['category'])) {
$indicators[] = 'Category: '.$data['category'];
}
if (! empty($data['created_from'])) {
$indicators[] = 'From: '.$data['created_from'];
}
if (! empty($data['created_to'])) {
$indicators[] = 'To: '.$data['created_to'];
}
return $indicators;
}),
])
->filtersFormMaxHeight('280px')
->actions([
Tables\Actions\ViewAction::make(),
Tables\Actions\EditAction::make(),
])
->bulkActions([
Tables\Actions\BulkActionGroup::make([
Tables\Actions\DeleteBulkAction::make(),
Tables\Actions\ForceDeleteBulkAction::make(),
Tables\Actions\RestoreBulkAction::make(),
]),
])
->headerActions([
// Tables\Actions\Action::make('Import Items')
// ->label('Import Items')
// ->form([
// Select::make('plant_id')
// // ->options(Plant::pluck('name', 'id')->toArray()) // Fetch plant names and IDs
// ->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();
// })
// ->label('Select Plant')
// ->required()
// // ->default(function () {
// // return optional(InvoiceValidation::latest()->first())->plant_id;
// // })
// ->afterStateUpdated(function ($state, callable $set, callable $get) {
// $set('item_code_file', null);
// })
// ->reactive(),
// FileUpload::make('item_code_file')
// ->label('Master Item Code')
// // ->required()
// ->preserveFilenames() // <- this keeps the original filename
// ->storeFiles(false) // prevent auto-storing, we will store manually
// ->reactive()
// ->required()
// ->disk('local') //'local' refers to the local storage disk defined in config/filesystems.php, typically pointing to storage/app.
// ->visible(fn (Get $get) => !empty($get('plant_id')))
// ->directory('uploads/temp'),
// ])
// ->action(function (array $data) {
// $uploadedFile = $data['item_code_file'];
// $disk = Storage::disk('local');
// $plantId = $data['plant_id'];
// // Get original filename
// $originalName = $uploadedFile->getClientOriginalName(); // e.g. 3RA0018732.xlsx
// $originalNameOnly = pathinfo($originalName, PATHINFO_FILENAME);
// // Store manually using storeAs to keep original name
// $path = $uploadedFile->storeAs('uploads/temp', $originalName, 'local'); // returns relative path
// $fullPath = Storage::disk('local')->path($path);
// if ($fullPath && file_exists($fullPath))
// {
// $rows = Excel::toArray(null, $fullPath)[0];
// if ((count($rows) - 1) <= 0)
// {
// Notification::make()
// ->title('Records Not Found')
// ->body("Import the valid 'Serial Invoice' file to proceed..!")
// ->danger()
// ->send();
// if ($disk->exists($path)) {
// $disk->delete($path);
// }
// return;
// }
// $invalidCategory = [];
// $materialCodes = [];
// $description = [];
// $invalidHourlyQuantity = [];
// $invalidUOM = [];
// $invalidPlantName = [];
// $seenItems = [];
// $uniqueInvalidCodes = [];
// $uniqueDesc = [];
// foreach ($rows as $index => $row)
// {
// if ($index == 0) continue; // Skip header
// $category = trim($row[0]);
// $materialCode = trim($row[1]);
// $desc = trim($row[2]);
// $hourlyQuantity = trim($row[3]);
// $uom = trim($row[4]);
// $plantName = trim($row[5]);
// if (strlen($materialCode) < 6) {
// $uniqueInvalidCodes[] = $materialCode;
// }
// else if (strlen($desc) < 7) {
// $uniqueDesc[] = $desc;
// }
// $key = $plantName . '|' . $materialCode;
// if (isset($seenItems[$key]))
// {
// $materialCodes[] = $materialCode;
// }
// else
// {
// $seenItems[$key] = true;
// }
// }
// if (!empty($uniqueInvalidCodes)) {
// Notification::make()
// ->title('Invalid Item Codes')
// ->body('The following item codes should contain minimum 6 digit alpha numeric values:<br>' . implode(', ', $uniqueInvalidCodes))
// ->danger()
// ->send();
// if ($disk->exists($path)) {
// $disk->delete($path);
// }
// return;
// }
// else if (!empty($uniqueMissingSerials)) {
// Notification::make()
// ->title('Missing Serial Numbers')
// ->body("The following item codes doesn't have valid serial number:<br>" . implode(', ', $uniqueMissingSerials))
// ->danger()
// ->send();
// if ($disk->exists($path)) {
// $disk->delete($path);
// }
// return;
// }
// else if (!empty($uniqueSerialCodes)) {
// Notification::make()
// ->title('Invalid Serial Number')
// ->body('The following serial numbers should contain minimum 9 digit alpha numeric values:<br>' . implode(', ', $uniqueSerialCodes))
// ->danger()
// ->send();
// if ($disk->exists($path)) {
// $disk->delete($path);
// }
// return;
// }
// else if (!empty($duplicateSerialCodes)) {
// Notification::make()
// ->title('Duplicate Serial Numbers')
// ->body('The following serial numbers are already exist in imported excel:<br>' . implode(', ', $duplicateSerialCodes))
// ->danger()
// ->send();
// if ($disk->exists($path)) {
// $disk->delete($path);
// }
// return;
// }
// $uniqueCodes = array_unique($materialCodes);
// $matchedItems = StickerMaster::with('item')
// ->whereHas('item', function ($query) use ($uniqueCodes) {
// $query->whereIn('code', $uniqueCodes);
// })
// ->get();
// $matchedCodes = $matchedItems->pluck('item.code')->toArray();
// $missingCodes = array_diff($uniqueCodes, $matchedCodes);
// if (!empty($missingCodes))
// {
// $missingCount = count($missingCodes);
// $message = $missingCount > 10 ? "'$missingCount' item codes are not found in database." : 'The following item codes are not found in database:<br>' . implode(', ', $missingCodes);
// Notification::make()
// ->title('Unknown Item Codes')
// ->body($message)
// ->danger()
// ->send();
// if ($disk->exists($path)) {
// $disk->delete($path);
// }
// return;
// }
// // Check which codes have a material_type set (not null)
// $invalidCodes = $matchedItems
// ->filter(fn ($sticker) => !empty($sticker->material_type)) //filter invalid
// ->pluck('item.code')
// ->toArray();
// if (count($invalidCodes) > 10)
// {
// Notification::make()
// ->title('Invalid item codes found')
// ->body('' . count($invalidCodes) . 'item codes found have material type.')
// ->danger()
// ->send();
// if ($disk->exists($path)) {
// $disk->delete($path);
// }
// return;
// }
// else if (count($invalidCodes) > 0)
// {
// Notification::make()
// ->title('Invalid item codes found')
// ->body('Material invoice Item Codes found : ' . implode(', ', $invalidCodes))
// ->danger()
// ->send();
// if ($disk->exists($path)) {
// $disk->delete($path);
// }
// return;
// }
// else
// {
// // Save full file path to session
// session(['uploaded_invoice_path' => $fullPath]);
// Notification::make()
// ->title('Serial invoice imported successfully.')
// ->success()
// ->send();
// }
// }
// })
// ->visible(function() {
// return Filament::auth()->user()->can('view import serial invoice');
// }),
ImportAction::make()
->label('Import Items')
->color('warning')
->importer(ItemImporter::class)
->visible(function () {
return Filament::auth()->user()->can('view import item');
}),
// ->maxRows(100000),
ExportAction::make()
// ->columnMapping(true)
->label('Export Items')
->color('warning')
// ->fileName("Items Report " . date('Y-m-d H:i:s'))
->exporter(ItemExporter::class)
->visible(function () {
return Filament::auth()->user()->can('view export item');
}),
// ->formats([
// ExportFormat::Xlsx,
// ExportFormat::Csv,
// ]),
]);
}
public static function getRelations(): array
{
return [
//
];
}
public static function getPages(): array
{
return [
'index' => Pages\ListItems::route('/'),
'create' => Pages\CreateItem::route('/create'),
'view' => Pages\ViewItem::route('/{record}'),
'edit' => Pages\EditItem::route('/{record}/edit'),
];
}
public static function getEloquentQuery(): Builder
{
return parent::getEloquentQuery()
->withoutGlobalScopes([
SoftDeletingScope::class,
]);
}
}

View File

@@ -0,0 +1,17 @@
<?php
namespace App\Filament\Resources\ItemResource\Pages;
use App\Filament\Resources\ItemResource;
use Filament\Actions;
use Filament\Resources\Pages\CreateRecord;
class CreateItem extends CreateRecord
{
protected static string $resource = ItemResource::class;
protected function getRedirectUrl(): string
{
return $this->getResource()::getUrl('create');
}
}

View File

@@ -0,0 +1,22 @@
<?php
namespace App\Filament\Resources\ItemResource\Pages;
use App\Filament\Resources\ItemResource;
use Filament\Actions;
use Filament\Resources\Pages\EditRecord;
class EditItem extends EditRecord
{
protected static string $resource = ItemResource::class;
protected function getHeaderActions(): array
{
return [
Actions\ViewAction::make(),
Actions\DeleteAction::make(),
Actions\ForceDeleteAction::make(),
Actions\RestoreAction::make(),
];
}
}

View File

@@ -0,0 +1,19 @@
<?php
namespace App\Filament\Resources\ItemResource\Pages;
use App\Filament\Resources\ItemResource;
use Filament\Actions;
use Filament\Resources\Pages\ListRecords;
class ListItems extends ListRecords
{
protected static string $resource = ItemResource::class;
protected function getHeaderActions(): array
{
return [
Actions\CreateAction::make(),
];
}
}

View File

@@ -0,0 +1,19 @@
<?php
namespace App\Filament\Resources\ItemResource\Pages;
use App\Filament\Resources\ItemResource;
use Filament\Actions;
use Filament\Resources\Pages\ViewRecord;
class ViewItem extends ViewRecord
{
protected static string $resource = ItemResource::class;
protected function getHeaderActions(): array
{
return [
Actions\EditAction::make(),
];
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,80 @@
<?php
namespace App\Filament\Resources\LineResource\Pages;
use App\Filament\Resources\LineResource;
use Filament\Actions;
use Filament\Resources\Pages\CreateRecord;
use Illuminate\Validation\ValidationException;
class CreateLine extends CreateRecord
{
protected static string $resource = LineResource::class;
protected function getRedirectUrl(): string
{
return $this->getResource()::getUrl('create');
}
protected function beforeCreate(): void
{
$errors = [];
if (!empty($this->data['lPlantError'])) {
$errors['lPlantError'] = ['Fix the errors before submitting.'];
}
if (!empty($this->data['lNameError'])) {
$errors['lNameError'] = ['Fix the errors before submitting.'];
}
if (!empty($this->data['lTypeError'])) {
$errors['lTypeError'] = ['Fix the errors before submitting.'];
}
if (!empty($this->data['work_group1_id_error'])) {
$errors['work_group1_id_error'] = ['Fix the errors before submitting.'];
}
if (!empty($this->data['work_group2_id_error'])) {
$errors['work_group2_id_error'] = ['Fix the errors before submitting.'];
}
if (!empty($this->data['work_group3_id_error'])) {
$errors['work_group1_id_error'] = ['Fix the errors before submitting.'];
}
if (!empty($this->data['work_group4_id_error'])) {
$errors['work_group4_id_error'] = ['Fix the errors before submitting.'];
}
if (!empty($this->data['work_group5_id_error'])) {
$errors['work_group5_id_error'] = ['Fix the errors before submitting.'];
}
if (!empty($this->data['work_group6_id_error'])) {
$errors['work_group6_id_error'] = ['Fix the errors before submitting.'];
}
if (!empty($this->data['work_group7_id_error'])) {
$errors['work_group7_id_error'] = ['Fix the errors before submitting.'];
}
if (!empty($this->data['work_group8_id_error'])) {
$errors['work_group8_id_error'] = ['Fix the errors before submitting.'];
}
if (!empty($this->data['work_group9_id_error'])) {
$errors['work_group9_id_error'] = ['Fix the errors before submitting.'];
}
//..warranty
if (!empty($this->data['work_group10_id_error'])) {
$errors['work_group10_id_error'] = ['Fix the errors before submitting.'];
}
if (!empty($errors)) {
throw ValidationException::withMessages($errors);
}
}
}

View File

@@ -0,0 +1,22 @@
<?php
namespace App\Filament\Resources\LineResource\Pages;
use App\Filament\Resources\LineResource;
use Filament\Actions;
use Filament\Resources\Pages\EditRecord;
class EditLine extends EditRecord
{
protected static string $resource = LineResource::class;
protected function getHeaderActions(): array
{
return [
Actions\ViewAction::make(),
Actions\DeleteAction::make(),
Actions\ForceDeleteAction::make(),
Actions\RestoreAction::make(),
];
}
}

View File

@@ -0,0 +1,19 @@
<?php
namespace App\Filament\Resources\LineResource\Pages;
use App\Filament\Resources\LineResource;
use Filament\Actions;
use Filament\Resources\Pages\ListRecords;
class ListLines extends ListRecords
{
protected static string $resource = LineResource::class;
protected function getHeaderActions(): array
{
return [
Actions\CreateAction::make(),
];
}
}

View File

@@ -0,0 +1,19 @@
<?php
namespace App\Filament\Resources\LineResource\Pages;
use App\Filament\Resources\LineResource;
use Filament\Actions;
use Filament\Resources\Pages\ViewRecord;
class ViewLine extends ViewRecord
{
protected static string $resource = LineResource::class;
protected function getHeaderActions(): array
{
return [
Actions\EditAction::make(),
];
}
}

View File

@@ -0,0 +1,200 @@
<?php
namespace App\Filament\Resources;
use App\Filament\Exports\LineStopExporter;
use App\Filament\Imports\LineStopImporter;
use App\Filament\Resources\LineStopResource\Pages;
use App\Filament\Resources\LineStopResource\RelationManagers;
use App\Models\LineStop;
use Doctrine\DBAL\Exception\InvalidColumnType\ColumnPrecisionRequired;
use Filament\Facades\Filament;
use Filament\Forms;
use Filament\Forms\Form;
use Filament\Resources\Resource;
use Filament\Tables;
use Filament\Tables\Actions\ImportAction;
use Filament\Tables\Table;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Database\Eloquent\SoftDeletingScope;
use Filament\Forms\Components\Section;
use Filament\Tables\Actions\ExportAction;
class LineStopResource extends Resource
{
protected static ?string $model = LineStop::class;
protected static ?string $navigationIcon = 'heroicon-o-rectangle-stack';
protected static ?string $navigationGroup = 'Master Entries';
protected static ?int $navigationSort = 7;
public static function form(Form $form): Form
{
return $form
->schema([
Section::make('')
->schema([
Forms\Components\TextInput::make('code')
->required()
->alphaNum()
->unique(ignoreRecord: true)
->minLength(3)
->placeholder('Scan the valid code')
->autofocus(true)
->autocapitalize(autocapitalize: 'characters')
->columnSpan(1)
->reactive()
->afterStateUpdated(function ($state, callable $set, callable $get) {
$code = $get('code');
if (!$code) {
$set('lsCodeError', 'Scan the valid code.');
return;
}
else
{
if (strlen($code) < 3) {
$set('lsCodeError', 'Code must be at least 3 digits.');
return;
}
else if (!preg_match('/^[a-zA-Z0-9]{3,}$/', $code)) {
$set('code',null);
$set('lsCodeError', 'Alpha-numeric only allowed.');
return;
}
$set('lsCodeError', null);
}
})
->extraAttributes(fn ($get) => [
'class' => $get('lsCodeError') ? 'border-red-500' : '',
])
->hint(fn ($get) => $get('lsCodeError') ? $get('lsCodeError') : null)
->hintColor('danger'),
Forms\Components\TextInput::make('reason')
->required()
->placeholder('Scan the valid reason')
->reactive()
->afterStateUpdated(function ($state, callable $set, callable $get) {
$reason = $get('reason');
if (!$reason) {
$set('lsReasonError', 'Scan the valid reason.');
return;
}
else
{
$set('lsReasonError', null);
}
})
->extraAttributes(fn ($get) => [
'class' => $get('lsReasonError') ? 'border-red-500' : '',
])
->hint(fn ($get) => $get('lsReasonError') ? $get('lsReasonError') : null)
->hintColor('danger')
->columnSpan(['default' => 1, 'sm' => 2]),
])
->columns(['default' => 1, 'sm' => 3]),
]);
}
public static function table(Table $table): Table
{
return $table
->columns([
// Tables\Columns\TextColumn::make('id')
// ->label('ID')
// ->numeric()
// ->sortable(),
Tables\Columns\TextColumn::make('No.')
->label('No.')
->getStateUsing(function ($record, $livewire, $column, $rowLoop) {
$paginator = $livewire->getTableRecords();
$perPage = method_exists($paginator, 'perPage') ? $paginator->perPage() : 10;
$currentPage = method_exists($paginator, 'currentPage') ? $paginator->currentPage() : 1;
return ($currentPage - 1) * $perPage + $rowLoop->iteration;
}),
Tables\Columns\TextColumn::make('code')
->label('Line Stop Code')
->alignCenter()
->sortable()
->searchable(),
Tables\Columns\TextColumn::make('reason')
->label('Line Stop Reason')
->alignCenter()
->sortable()
->searchable(),
Tables\Columns\TextColumn::make('created_at')
->label('Created At')
->dateTime()
->alignCenter()
->sortable(),
Tables\Columns\TextColumn::make('updated_at')
->label('Updated At')
->dateTime()
->alignCenter()
->sortable()
->toggleable(isToggledHiddenByDefault: true),
Tables\Columns\TextColumn::make('deleted_at')
->label('Deleted At')
->dateTime()
->alignCenter()
->sortable()
->toggleable(isToggledHiddenByDefault: true),
])
->filters([
Tables\Filters\TrashedFilter::make(),
])
->actions([
Tables\Actions\ViewAction::make(),
Tables\Actions\EditAction::make(),
])
->bulkActions([
Tables\Actions\BulkActionGroup::make([
Tables\Actions\DeleteBulkAction::make(),
Tables\Actions\ForceDeleteBulkAction::make(),
Tables\Actions\RestoreBulkAction::make(),
]),
])
->headerActions([
ImportAction::make()
->label('Import Line Stops')
->color('warning')
->importer(LineStopImporter::class)
->visible(function() {
return Filament::auth()->user()->can('view import line stop');
}),
ExportAction::make()
->label('Export Line Stops')
->color('warning')
->exporter(LineStopExporter::class)
->visible(function() {
return Filament::auth()->user()->can('view export line stop');
}),
]);
}
public static function getRelations(): array
{
return [
//
];
}
public static function getPages(): array
{
return [
'index' => Pages\ListLineStops::route('/'),
'create' => Pages\CreateLineStop::route('/create'),
'view' => Pages\ViewLineStop::route('/{record}'),
'edit' => Pages\EditLineStop::route('/{record}/edit'),
];
}
public static function getEloquentQuery(): Builder
{
return parent::getEloquentQuery()
->withoutGlobalScopes([
SoftDeletingScope::class,
]);
}
}

View File

@@ -0,0 +1,17 @@
<?php
namespace App\Filament\Resources\LineStopResource\Pages;
use App\Filament\Resources\LineStopResource;
use Filament\Actions;
use Filament\Resources\Pages\CreateRecord;
class CreateLineStop extends CreateRecord
{
protected static string $resource = LineStopResource::class;
protected function getRedirectUrl(): string
{
return $this->getResource()::getUrl('create');
}
}

Some files were not shown because too many files have changed in this diff Show More