26 Commits

Author SHA1 Message Date
1ab7ed2da9 Merge pull request 'Added sticker deatil importer and exporter' (#27) from ranjith-dev into master
Some checks failed
Scan for leaked secrets using Kingfisher / kingfisher-secrets-scan (push) Has been cancelled
Reviewed-on: #27
2025-12-22 11:41:57 +00:00
9ecd04f0e3 Merge pull request 'Added sticker detail resource page' (#26) from ranjith-dev into master
Some checks failed
Scan for leaked secrets using Kingfisher / kingfisher-secrets-scan (push) Has been cancelled
Reviewed-on: #26
2025-12-22 11:41:04 +00:00
53179ea538 Merge pull request 'Added sticker detail model file' (#25) from ranjith-dev into master
Some checks failed
Scan for leaked secrets using Kingfisher / kingfisher-secrets-scan (push) Has been cancelled
Reviewed-on: #25
2025-12-22 11:39:46 +00:00
b4e24c581e Merge pull request 'Added sticker details migration file' (#24) from ranjith-dev into master
Some checks failed
Scan for leaked secrets using Kingfisher / kingfisher-secrets-scan (push) Has been cancelled
Reviewed-on: #24
2025-12-22 11:38:28 +00:00
4938fa62a7 Merge pull request 'Added sticker structure policy file' (#23) from ranjith-dev into master
Some checks failed
Scan for leaked secrets using Kingfisher / kingfisher-secrets-scan (push) Has been cancelled
Reviewed-on: #23
2025-12-22 11:34:44 +00:00
01f6288c63 Merge pull request 'Added importer and exporter of sticker structure detail' (#22) from ranjith-dev into master
Some checks failed
Scan for leaked secrets using Kingfisher / kingfisher-secrets-scan (push) Has been cancelled
Reviewed-on: #22
2025-12-22 11:33:09 +00:00
c9c7c38088 Merge pull request 'Added sticker structure detail resource pages' (#21) from ranjith-dev into master
Some checks failed
Scan for leaked secrets using Kingfisher / kingfisher-secrets-scan (push) Has been cancelled
Reviewed-on: #21
2025-12-22 11:32:08 +00:00
90cfe9ef0d Merge pull request 'Added sticker structure detail model file' (#20) from ranjith-dev into master
Some checks failed
Scan for leaked secrets using Kingfisher / kingfisher-secrets-scan (push) Has been cancelled
Reviewed-on: #20
2025-12-22 11:30:56 +00:00
aa806f2fe3 Merge pull request 'Added sticker structure detail migration file' (#19) from ranjith-dev into master
Some checks failed
Scan for leaked secrets using Kingfisher / kingfisher-secrets-scan (push) Has been cancelled
Reviewed-on: #19
2025-12-22 11:30:11 +00:00
0eb6f76ca6 Merge pull request 'Enhance Gemini review step to handle errors and provide feedback on review status' (#18) from ranjith-dev into master
All checks were successful
Scan for leaked secrets using Kingfisher / kingfisher-secrets-scan (push) Successful in 10s
Reviewed-on: #18
2025-12-18 06:34:16 +00:00
73366ccd70 Merge pull request 'Update Gemini review step to use gemini-pro model for code analysis' (#17) from ranjith-dev into master
Some checks failed
Scan for leaked secrets using Kingfisher / kingfisher-secrets-scan (push) Has been cancelled
Reviewed-on: #17
2025-12-18 06:31:07 +00:00
acbecedce9 Merge pull request 'Update Gemini review step to use gemini-1.5-flash model for code analysis' (#16) from ranjith-dev into master
Some checks failed
Scan for leaked secrets using Kingfisher / kingfisher-secrets-scan (push) Has been cancelled
Reviewed-on: #16
2025-12-18 06:28:15 +00:00
614d89932b Merge pull request 'Update Gemini review step to use GPT-5-mini model for code analysis' (#15) from ranjith-dev into master
Some checks failed
Scan for leaked secrets using Kingfisher / kingfisher-secrets-scan (push) Has been cancelled
Reviewed-on: #15
2025-12-18 06:26:56 +00:00
c839c6fdbc Merge pull request 'Remove unnecessary blank line in Gemini PR Review workflow' (#14) from ranjith-dev into master
All checks were successful
Scan for leaked secrets using Kingfisher / kingfisher-secrets-scan (push) Successful in 11s
Reviewed-on: #14
2025-12-18 05:16:54 +00:00
d9445a9d4b Merge pull request 'Refactor Gemini PR Review workflow' (#13) from ranjith-dev into master
All checks were successful
Scan for leaked secrets using Kingfisher / kingfisher-secrets-scan (push) Successful in 10s
Reviewed-on: #13
2025-12-18 04:48:44 +00:00
50476c8a2c Merge pull request 'Added nav group name in ocr validation resource page' (#12) from ranjith-dev into master
All checks were successful
Scan for leaked secrets using Kingfisher / kingfisher-secrets-scan (push) Successful in 10s
Reviewed-on: #12
2025-12-17 06:22:14 +00:00
c57cfe71ca Merge pull request 'Added nav group for web capture page' (#11) from ranjith-dev into master
Some checks failed
Scan for leaked secrets using Kingfisher / kingfisher-secrets-scan (push) Has been cancelled
Reviewed-on: #11
2025-12-17 06:21:40 +00:00
96c08c34c1 Merge pull request 'Added nav group in reject reason resource page' (#10) from ranjith-dev into master
Some checks failed
Scan for leaked secrets using Kingfisher / kingfisher-secrets-scan (push) Has been cancelled
Reviewed-on: #10
2025-12-17 06:20:01 +00:00
19cf7c8edd Merge pull request 'Added nav group for production reject reason resource page' (#9) from ranjith-dev into master
Some checks failed
Scan for leaked secrets using Kingfisher / kingfisher-secrets-scan (push) Has been cancelled
Reviewed-on: #9
2025-12-17 06:19:03 +00:00
66086dd2d7 Merge pull request 'Added nav group in product characteristics resource page' (#8) from ranjith-dev into master
Some checks failed
Scan for leaked secrets using Kingfisher / kingfisher-secrets-scan (push) Has been cancelled
Reviewed-on: #8
2025-12-17 06:16:38 +00:00
5da724c9a4 Merge pull request 'Added nav group in gr master resource page' (#7) from ranjith-dev into master
Some checks failed
Scan for leaked secrets using Kingfisher / kingfisher-secrets-scan (push) Has been cancelled
Reviewed-on: #7
2025-12-17 06:15:52 +00:00
6b723c0929 Merge pull request 'Added navigation sort for sticker mapping resource page' (#6) from ranjith-dev into master
Some checks failed
Scan for leaked secrets using Kingfisher / kingfisher-secrets-scan (push) Has been cancelled
Reviewed-on: #6
2025-12-17 06:13:44 +00:00
8e20d0732d Merge pull request 'Added nav group for sticker printing resource page' (#5) from ranjith-dev into master
Some checks failed
Scan for leaked secrets using Kingfisher / kingfisher-secrets-scan (push) Has been cancelled
Reviewed-on: #5
2025-12-17 06:11:56 +00:00
1d8fb1c9aa Merge pull request 'Added nav group for sticker master mapping resource' (#4) from ranjith-dev into master
Some checks failed
Scan for leaked secrets using Kingfisher / kingfisher-secrets-scan (push) Has been cancelled
Reviewed-on: #4
2025-12-17 06:11:07 +00:00
33bbce47ba Merge pull request 'Added navigation group for class characteristics' (#3) from ranjith-dev into master
Some checks failed
Scan for leaked secrets using Kingfisher / kingfisher-secrets-scan (push) Has been cancelled
Reviewed-on: #3
2025-12-17 06:08:01 +00:00
860ff96134 Merge pull request 'Added driver master migration file' (#2) from fix-migration into master
All checks were successful
Scan for leaked secrets using Kingfisher / kingfisher-secrets-scan (push) Successful in 10s
Reviewed-on: #2
2025-12-17 03:52:20 +00:00
142 changed files with 2361 additions and 16406 deletions

View File

@@ -1,62 +0,0 @@
<?php
namespace App\Exports;
use Maatwebsite\Excel\Concerns\FromCollection;
use Maatwebsite\Excel\Concerns\FromArray;
use Maatwebsite\Excel\Concerns\WithHeadings;
use Maatwebsite\Excel\Concerns\WithMapping;
class ProductionPlanExport implements FromArray, WithHeadings, WithMapping
{
protected array $data;
protected array $dates;
public function __construct(array $data, array $dates)
{
$this->data = $data;
$this->dates = $dates;
}
public function array(): array
{
return $this->data;
}
public function headings(): array
{
$headings = [
'Plant Name',
'Line Name',
'Item Code',
];
// Add dynamic headings for each date: Target / Produced
foreach ($this->dates as $date) {
$headings[] = $date . ' - Target Plan';
$headings[] = $date . ' - Produced Quantity';
}
return $headings;
}
public function map($row): array
{
$mapped = [
$row['plant_name'] ?? '',
$row['line_name'] ?? '',
$row['item_code'] ?? '',
];
// Add daily target and produced quantity for each date
foreach ($this->dates as $date) {
// $mapped[] = $row['daily_target_dynamic'] ?? 0;
$mapped[] = $row['daily_target_dynamic'][$date] ?? '-';
$mapped[] = $row['produced_quantity'][$date] ?? 0;
}
return $mapped;
}
}

View File

@@ -1,44 +0,0 @@
<?php
namespace App\Filament\Exports;
use App\Models\EmployeeMaster;
use Filament\Actions\Exports\ExportColumn;
use Filament\Actions\Exports\Exporter;
use Filament\Actions\Exports\Models\Export;
class EmployeeMasterExporter extends Exporter
{
protected static ?string $model = EmployeeMaster::class;
public static function getColumns(): array
{
return [
ExportColumn::make('id')
->label('ID'),
ExportColumn::make('plant.name'),
ExportColumn::make('name'),
ExportColumn::make('code'),
ExportColumn::make('department'),
ExportColumn::make('designation'),
ExportColumn::make('email'),
ExportColumn::make('mobile_number'),
ExportColumn::make('created_at'),
ExportColumn::make('updated_at'),
ExportColumn::make('created_by'),
ExportColumn::make('updated_by'),
ExportColumn::make('deleted_at'),
];
}
public static function getCompletedNotificationBody(Export $export): string
{
$body = 'Your employee master export has completed and ' . number_format($export->successful_rows) . ' ' . str('row')->plural($export->successful_rows) . ' exported.';
if ($failedRowsCount = $export->getFailedRowsCount()) {
$body .= ' ' . number_format($failedRowsCount) . ' ' . str('row')->plural($failedRowsCount) . ' failed to export.';
}
return $body;
}
}

View File

@@ -29,8 +29,6 @@ class StickerDetailExporter extends Exporter
->label('ELEMENT ID'),
ExportColumn::make('element_type')
->label('ELEMENT TYPE'),
ExportColumn::make('characteristics_type')
->label('CHARACTERISTICS TYPE'),
ExportColumn::make('string_value')
->label('STRING VALUE'),
ExportColumn::make('string_font')
@@ -49,8 +47,6 @@ class StickerDetailExporter extends Exporter
->label('SHAPE NAME'),
ExportColumn::make('shape_pen_size')
->label('SHAPE PEN SIZE'),
ExportColumn::make('curve_radius')
->label('CURVE RADIUS'),
ExportColumn::make('shape_x1_value')
->label('SHAPE X1 VALUE'),
ExportColumn::make('shape_y1_value')
@@ -59,6 +55,10 @@ class StickerDetailExporter extends Exporter
->label('SHAPE X2 VALUE'),
ExportColumn::make('shape_y2_value')
->label('SHAPE Y2 VALUE'),
ExportColumn::make('image_path')
->label('IMAGE PATH'),
ExportColumn::make('image_type')
->label('IMAGE TYPE'),
ExportColumn::make('image_x')
->label('IMAGE X'),
ExportColumn::make('image_y')

View File

@@ -21,117 +21,28 @@ class StickerMappingMasterExporter extends Exporter
// Increment and return the row number
return ++$rowNumber;
}),
ExportColumn::make('plant.code')
->label('PLANT CODE'),
ExportColumn::make('itemCharacteristic.item.code')
ExportColumn::make('plant.name')
->label('PLANT'),
ExportColumn::make('item.code')
->label('ITEM CODE'),
ExportColumn::make('sticker_structure1_id')
->label('STICKER 1')
->getStateUsing(function ($record) {
return $record->sticker1Structure?->sticker_id ?? '-';
}),
ExportColumn::make('sticker1_machine_id')
->label('WC STICKER 1')
->getStateUsing(function ($record) {
return $record->sticker1Machine?->work_center ?? '-';
}),
ExportColumn::make('sticker1_print_ip')
->label('STICKER 1 PRINT IP'),
ExportColumn::make('sticker_structure2_id')
->label('STICKER 2')
->getStateUsing(function ($record) {
return $record->sticker2Structure?->sticker_id ?? '-';
}),
ExportColumn::make('sticker2_machine_id')
->label('WC STICKER 2')
->getStateUsing(function ($record) {
return $record->sticker2Machine?->work_center ?? '-';
}),
ExportColumn::make('sticker2_print_ip')
->label('STICKER 2 PRINT IP'),
ExportColumn::make('sticker_structure3_id')
->label('STICKER 3')
->getStateUsing(function ($record) {
return $record->sticker3Structure?->sticker_id ?? '-';
}),
ExportColumn::make('sticker3_machine_id')
->label('WC STICKER 3')
->getStateUsing(function ($record) {
return $record->sticker3Machine?->work_center ?? '-';
}),
ExportColumn::make('sticker3_print_ip')
->label('STICKER 3 PRINT IP'),
ExportColumn::make('sticker_structure4_id')
->label('STICKER 4')
->getStateUsing(function ($record) {
return $record->sticker4Structure?->sticker_id ?? '-';
}),
ExportColumn::make('sticker4_machine_id')
->label('WC STICKER 4')
->getStateUsing(function ($record) {
return $record->sticker4Machine?->work_center ?? '-';
}),
ExportColumn::make('sticker4_print_ip')
->label('STICKER 4 PRINT IP'),
ExportColumn::make('sticker_structure5_id')
->label('STICKER 5')
->getStateUsing(function ($record) {
return $record->sticker5Structure?->sticker_id ?? '-';
}),
ExportColumn::make('sticker5_machine_id')
->label('WC STICKER 5')
->getStateUsing(function ($record) {
return $record->sticker5Machine?->work_center ?? '-';
}),
ExportColumn::make('sticker5_print_ip')
->label('STICKER 5 PRINT IP'),
ExportColumn::make('sticker_structure6_id')
->label('STICKER 6')
->getStateUsing(function ($record) {
return $record->sticker6Structure?->sticker_id ?? '-';
}),
ExportColumn::make('sticker6_machine_id')
->label('WC STICKER 6')
->getStateUsing(function ($record) {
return $record->sticker6Machine?->work_center ?? '-';
}),
ExportColumn::make('sticker6_print_ip')
->label('STICKER 6 PRINT IP'),
ExportColumn::make('sticker_structure7_id')
->label('STICKER 7')
->getStateUsing(function ($record) {
return $record->sticker7Structure?->sticker_id ?? '-';
}),
ExportColumn::make('sticker7_machine_id')
->label('WC STICKER 7')
->getStateUsing(function ($record) {
return $record->sticker2Machine?->work_center ?? '-';
}),
ExportColumn::make('sticker7_print_ip')
->label('STICKER 7 PRINT IP'),
ExportColumn::make('sticker_structure8_id')
->label('STICKER 8')
->getStateUsing(function ($record) {
return $record->sticker8Structure?->sticker_id ?? '-';
}),
ExportColumn::make('sticker8_machine_id')
->label('WC STICKER 8')
->getStateUsing(function ($record) {
return $record->sticker8Machine?->work_center ?? '-';
}),
ExportColumn::make('sticker8_print_ip')
->label('STICKER 8 PRINT IP'),
ExportColumn::make('sticker1')
->label('STICKER LABEL 1'),
ExportColumn::make('sticker2')
->label('STICKER LABEL 2'),
ExportColumn::make('sticker3')
->label('STICKER LABEL 3'),
ExportColumn::make('sticker4')
->label('STICKER LABEL 4'),
ExportColumn::make('sticker5')
->label('STICKER LABEL 5'),
ExportColumn::make('created_at')
->label('CREATED AT'),
ExportColumn::make('updated_at')
->label('UPDATED AT'),
ExportColumn::make('created_by')
->label('CREATED BY'),
ExportColumn::make('updated_by')
->label('UPDATED BY'),
ExportColumn::make('deleted_at')
->enabledByDefault(false)
->label('DELETED AT'),
ExportColumn::make('updated_by'),
ExportColumn::make('deleted_at'),
];
}

View File

@@ -13,43 +13,21 @@ class StickerStructureDetailExporter extends Exporter
public static function getColumns(): array
{
static $rowNumber = 0;
return [
ExportColumn::make('no')
->label('NO')
->state(function ($record) use (&$rowNumber) {
// Increment and return the row number
return ++$rowNumber;
}),
ExportColumn::make('plant.code')
->label('PLANT CODE'),
ExportColumn::make('itemCharacteristic.item.code')
->label('ITEM CODE'),
ExportColumn::make('sticker_id')
->label('STICKER ID'),
ExportColumn::make('sticker_width')
->label('STICKER WIDTH'),
ExportColumn::make('sticker_height')
->label('STICKER HEIGHT'),
ExportColumn::make('sticker_lmargin')
->label('STICKER LEFT MARGIN'),
ExportColumn::make('sticker_rmargin')
->label('STICKER RIGHT MARGIN'),
ExportColumn::make('sticker_tmargin')
->label('STICKER TOP MARGIN'),
ExportColumn::make('sticker_bmargin')
->label('STICKER BOTTOM MARGIN'),
ExportColumn::make('created_at')
->label('CREATED AT'),
ExportColumn::make('updated_at')
->label('UPDATED AT'),
ExportColumn::make('created_by')
->label('CREATED BY'),
ExportColumn::make('updated_by')
->label('UPDATED BY'),
ExportColumn::make('deleted_at')
->enabledByDefault(false)
->label('DELETED AT'),
ExportColumn::make('id')
->label('ID'),
ExportColumn::make('sticker_id'),
ExportColumn::make('sticker_width'),
ExportColumn::make('sticker_height'),
ExportColumn::make('sticker_lmargin'),
ExportColumn::make('sticker_rmargin'),
ExportColumn::make('sticker_tmargin'),
ExportColumn::make('sticker_bmargin'),
ExportColumn::make('created_at'),
ExportColumn::make('updated_at'),
ExportColumn::make('created_by'),
ExportColumn::make('updated_by'),
ExportColumn::make('deleted_at'),
];
}

View File

@@ -1,53 +0,0 @@
<?php
namespace App\Filament\Imports;
use App\Models\EmployeeMaster;
use Filament\Actions\Imports\ImportColumn;
use Filament\Actions\Imports\Importer;
use Filament\Actions\Imports\Models\Import;
class EmployeeMasterImporter extends Importer
{
protected static ?string $model = EmployeeMaster::class;
public static function getColumns(): array
{
return [
ImportColumn::make('plant')
->requiredMapping()
->relationship()
->rules(['required']),
ImportColumn::make('name'),
ImportColumn::make('code'),
ImportColumn::make('department'),
ImportColumn::make('designation'),
ImportColumn::make('email')
->rules(['email']),
ImportColumn::make('mobile_number'),
ImportColumn::make('created_by'),
ImportColumn::make('updated_by'),
];
}
public function resolveRecord(): ?EmployeeMaster
{
// return EmployeeMaster::firstOrNew([
// // Update existing records, matching them by `$this->data['column_name']`
// 'email' => $this->data['email'],
// ]);
return new EmployeeMaster();
}
public static function getCompletedNotificationBody(Import $import): string
{
$body = 'Your employee master import has completed and ' . number_format($import->successful_rows) . ' ' . str('row')->plural($import->successful_rows) . ' imported.';
if ($failedRowsCount = $import->getFailedRowsCount()) {
$body .= ' ' . number_format($failedRowsCount) . ' ' . str('row')->plural($failedRowsCount) . ' failed to import.';
}
return $body;
}
}

View File

@@ -3,7 +3,6 @@
namespace App\Filament\Imports;
use App\Models\Block;
use App\Models\Item;
use App\Models\Line;
use App\Models\Plant;
use App\Models\ProductionPlan;
@@ -24,33 +23,11 @@ class ProductionPlanImporter extends Importer
public static function getColumns(): array
{
return [
// ImportColumn::make('created_at')
// ->requiredMapping()
// ->exampleHeader('Created DateTime')
// ->example(['01-01-2025 08:00:00', '01-01-2025 19:30:00'])
// ->label('Created DateTime')
// ->rules(['required']),
ImportColumn::make('plant')
ImportColumn::make('created_at')
->requiredMapping()
->exampleHeader('Plant Code')
->example(['1000', '1000'])
->label('Plant Code')
->relationship(resolveUsing: 'code')
->rules(['required']),
ImportColumn::make('line')
->requiredMapping()
->exampleHeader('Line Name')
->example(['4 inch pump line', '4 inch pump line'])
->label('Line Name')
->relationship(resolveUsing: 'name')
->rules(['required']),
ImportColumn::make('item')
->requiredMapping()
->exampleHeader('Item Code')
->example(['123456', '210987'])
->label('Item Code')
->relationship(resolveUsing: 'code')
->exampleHeader('Created DateTime')
->example(['01-01-2025 08:00:00', '01-01-2025 19:30:00'])
->label('Created DateTime')
->rules(['required']),
ImportColumn::make('plan_quantity')
->requiredMapping()
@@ -59,111 +36,175 @@ class ProductionPlanImporter extends Importer
->label('Plan Quantity')
->numeric()
->rules(['required', 'integer']),
// ImportColumn::make('production_quantity')
// ->requiredMapping()
// ->exampleHeader('Production Quantity')
// ->example(['0', '0'])
// ->label('Production Quantity')
// ->numeric()
// ->rules(['required', 'integer']),
// ImportColumn::make('block_reference')
// ->requiredMapping() // Or optionalMapping() if not always present
// ->exampleHeader('Block Name')
// ->example(['Block A', 'Block A'])
// ->label('Block Name')
// ->rules(['required']), // Or remove if not required
// ImportColumn::make('shift')
// ->requiredMapping()
// ->exampleHeader('Shift Name') // ID
// ->example(['Day', 'Night']) // '2', '7'
// ->label('Shift Name') // ID
// ->relationship(resolveUsing: 'name')
// ->rules(['required']),
// ImportColumn::make('updated_at')
// ->requiredMapping()
// ->exampleHeader('Updated DateTime')
// ->example(['01-01-2025 08:00:00', '01-01-2025 19:30:00'])
// ->label('Updated DateTime')
// ->rules(['required']),
// ImportColumn::make('operator_id')
// ->requiredMapping()
// ->exampleHeader('Operator ID')
// ->example([Filament::auth()->user()->name, Filament::auth()->user()->name])
// ->label('Operator ID')
// ->rules(['required']),
ImportColumn::make('production_quantity')
->requiredMapping()
->exampleHeader('Production Quantity')
->example(['0', '0'])
->label('Production Quantity')
->numeric()
->rules(['required', 'integer']),
ImportColumn::make('line')
->requiredMapping()
->exampleHeader('Line Name')
->example(['4 inch pump line', '4 inch pump line'])
->label('Line Name')
->relationship(resolveUsing:'name')
->rules(['required']),
ImportColumn::make('block_reference')
->requiredMapping() // Or optionalMapping() if not always present
->exampleHeader('Block Name')
->example(['Block A', 'Block A'])
->label('Block Name')
->rules(['required']), // Or remove if not required
ImportColumn::make('shift')
->requiredMapping()
->exampleHeader('Shift Name') //ID
->example(['Day', 'Night']) //'2', '7'
->label('Shift Name') // ID
->relationship(resolveUsing: 'name')
->rules(['required']),
ImportColumn::make('plant')
->requiredMapping()
->exampleHeader('Plant Name')
->example(['Ransar Industries-I', 'Ransar Industries-I'])
->label('Plant Name')
->relationship(resolveUsing:'name')
->rules(['required']),
ImportColumn::make('updated_at')
->requiredMapping()
->exampleHeader('Updated DateTime')
->example(['01-01-2025 08:00:00', '01-01-2025 19:30:00'])
->label('Updated DateTime')
->rules(['required']),
ImportColumn::make('operator_id')
->requiredMapping()
->exampleHeader('Operator ID')
->example([Filament::auth()->user()->name, Filament::auth()->user()->name])
->label('Operator ID')
->rules(['required']),
];
}
public function resolveRecord(): ?ProductionPlan
{
$warnMsg = [];
$plantCod = $this->data['plant'];
$itemCod = $this->data['item'];
$plant = null;
$plant = Plant::where('name', $this->data['plant'])->first();
$line = null;
$block = null;
if (Str::length($plantCod) < 4 || ! is_numeric($plantCod) || ! preg_match('/^[1-9]\d{3,}$/', $plantCod)) {
$warnMsg[] = 'Invalid plant code found';
} else {
$plant = Plant::where('code', $plantCod)->first();
if (!$plant) {
$warnMsg[] = "Plant not found";
}
if (! $plant) {
$warnMsg[] = 'Plant not found';
} else {
else {
$line = Line::where('name', $this->data['line'])->where('plant_id', $plant->id)->first();
//block_reference
$block = Block::where('name', $this->data['block_reference'])->where('plant_id', $plant->id)->first();
}
if (!$line) {
$warnMsg[] = "Line not found";
}
$shift = null;
if (!$block) {
$warnMsg[] = "Block not found";
}
else {
$shift = Shift::where('name', $this->data['shift'])->where('plant_id', $plant->id)->where('block_id', $block->id)->first();
}
//$shift = Shift::where('id', $this->data['shift'])->where('plant_id', $plant->id)->first();
if (!$shift) {
$warnMsg[] = "Shift not found";
}
if (Str::length($this->data['plan_quantity']) < 0 || !is_numeric($this->data['plan_quantity']) || $this->data['plan_quantity'] <= 0) {
$warnMsg[] = "Invalid plan quantity found";
}
if (Str::length($this->data['production_quantity']) < 0 || !is_numeric($this->data['production_quantity']) || $this->data['production_quantity'] < 0) {
$warnMsg[] = "Invalid production quantity found";
}
if (! $line) {
$warnMsg[] = 'Line not found';
$fromDate = $this->data['created_at'];
$toDate = $this->data['updated_at'];
$formats = ['d-m-Y H:i', 'd-m-Y H:i:s']; //'07-05-2025 08:00' or '07-05-2025 08:00:00'
$fdateTime = null;
$tdateTime = null;
// Try parsing with multiple formats
foreach ($formats as $format) {
try {
$fdateTime = Carbon::createFromFormat($format, $fromDate);
break;
} catch (\Exception $e) {
// Optionally collect warning messages
// $warnMsg[] = "Date format mismatch with format: $format";
}
}
if (Str::length($itemCod) < 6 || ! is_numeric($itemCod)) {
$warnMsg[] = 'Invalid item code found';
} else {
$item = Item::where('code', $itemCod)->first();
foreach ($formats as $format) {
try {
$tdateTime = Carbon::createFromFormat($format, $toDate);
break;
} catch (\Exception $e) {
// Optionally collect warning messages
// $warnMsg[] = "Date format mismatch with format: $format";
}
}
if (! $item) {
$warnMsg[] = 'Item not found';
$fDateOnly = '';
if (!isset($fdateTime)) {
// throw new \Exception('Invalid date time format');
$warnMsg[] = "Invalid 'Created DateTime' format. Expected DD-MM-YYYY HH:MM:SS";
}
else {
$fDateOnly = $fdateTime->toDateString();
}
if (!isset($tdateTime)) {
$warnMsg[] = "Invalid 'Updated DateTime' format. Expected DD-MM-YYYY HH:MM:SS";
}
$plantId = $plant->id;
$itemAgaPlant = Item::where('plant_id', $plantId)->where('code', $itemCod)->first();
if(!$itemAgaPlant){
$warnMsg[] = 'Item not found against plant code';
if (isset($fdateTime) && isset($tdateTime)) {
if ($fdateTime->greaterThan($tdateTime)) {
$warnMsg[] = "'Created DataTime' is greater than 'Updated DateTime'.";
}
}
$user = Filament::auth()->user();
// if (!$fromDate) {
// $warnMsg[] = "Invalid 'Created DateTime' format. Expected DD-MM-YYYY HH:MM:SS";
// }
// else if (!$toDate) {
// $warnMsg[] = "Invalid 'Updated DateTime' format. Expected DD-MM-YYYY HH:MM:SS";
// }
$operatorName = $user->name;
if (Str::length($this->data['plan_quantity']) < 0 || ! is_numeric($this->data['plan_quantity']) || $this->data['plan_quantity'] <= 0) {
$warnMsg[] = 'Invalid plan quantity found';
$user = User::where('name', $this->data['operator_id'])->first();
if (!$user) {
$warnMsg[] = "Operator ID not found";
}
if (! empty($warnMsg)) {
if (!empty($warnMsg)) {
throw new RowImportFailedException(implode(', ', $warnMsg));
} else {
}
else { //if (empty($warnMsg))
$productionPlan = ProductionPlan::where('plant_id', $plant->id)
->where('line_id', $line->id)
->where('item_id', $itemAgaPlant->id)
->latest()
->first();
->where('shift_id', $shift->id)
->where('line_id', $line->id)
->whereDate('created_at', $fDateOnly)
// ->where('plan_quantity', $productionQuantity->plan_quantity)
->latest()
->first();
if ($productionPlan) {
// if($productionPlan->production_quantity)
// {
// throw new RowImportFailedException("{$productionPlan->created_at}, {$productionPlan->production_quantity}");
// }
// $warnMsg[] = "Production plan already exist on '{$fDateOnly}'!";
$productionPlan->update([
'plan_quantity' => $this->data['plan_quantity'],
'operator_id' => $operatorName,
// 'production_quantity' => $productionPlan->production_quantity,
// 'created_at' => $productionPlan->created_at,//$fdateTime->format('Y-m-d H:i:s'),
// 'updated_at' => $tdateTime->format('Y-m-d H:i:s'),
'operator_id' => $this->data['operator_id'],
]);
$productionPlan->save();
return null;
}
}
@@ -171,23 +212,28 @@ class ProductionPlanImporter extends Importer
ProductionPlan::updateOrCreate([
'plant_id' => $plant->id,
'line_id' => $line->id,
'item_id' => $itemAgaPlant->id,
// 'shift_id' => $shift->id,
'shift_id' => $shift->id,
'plan_quantity' => $this->data['plan_quantity'],
'created_at' =>now(),
'updated_at' => now(),
'operator_id' => $operatorName,
'production_quantity' => $this->data['production_quantity'],
'created_at' => $fdateTime->format('Y-m-d H:i:s'),//$this->data['created_at'],
'updated_at' => $tdateTime->format('Y-m-d H:i:s'),//$this->data['updated_at'],
'operator_id' => $this->data['operator_id'],
]);
return null;
// return ProductionPlan::firstOrNew([
// // Update existing records, matching them by `$this->data['column_name']`
// 'email' => $this->data['email'],
// ]);
// return new ProductionPlan();
}
public static function getCompletedNotificationBody(Import $import): string
{
$body = 'Your production plan import has completed and '.number_format($import->successful_rows).' '.str('row')->plural($import->successful_rows).' imported.';
$body = 'Your production plan import has completed and ' . number_format($import->successful_rows) . ' ' . str('row')->plural($import->successful_rows) . ' imported.';
if ($failedRowsCount = $import->getFailedRowsCount()) {
$body .= ' '.number_format($failedRowsCount).' '.str('row')->plural($failedRowsCount).' failed to import.';
$body .= ' ' . number_format($failedRowsCount) . ' ' . str('row')->plural($failedRowsCount) . ' failed to import.';
}
return $body;

View File

@@ -2,14 +2,10 @@
namespace App\Filament\Imports;
use App\Models\Plant;
use App\Models\StickerDetail;
use App\Models\StickerStructureDetail;
use App\Models\User;
use Filament\Actions\Imports\ImportColumn;
use Filament\Actions\Imports\Importer;
use Filament\Actions\Imports\Models\Import;
use Filament\Actions\Imports\Exceptions\RowImportFailedException;
class StickerDetailImporter extends Importer
{
@@ -18,295 +14,50 @@ class StickerDetailImporter extends Importer
public static function getColumns(): array
{
return [
ImportColumn::make('sticker_structure_detail_id')
ImportColumn::make('stickerStructureDetail')
->requiredMapping()
->exampleHeader('Sticker ID')
->example('123456')
->label('STICKER ID')
->relationship()
->rules(['required']),
ImportColumn::make('design_element_type')
->requiredMapping()
->exampleHeader('Design Element Type')
->label('DESIGN ELEMENT TYPE')
->example('Text/Shape/Image/QR'),
ImportColumn::make('element_id')
->requiredMapping()
->exampleHeader('Element ID')
->label('ELEMENT ID')
->example('001'),
ImportColumn::make('element_type')
->requiredMapping()
->exampleHeader('Element Type')
->label('ELEMENT TYPE')
->example('Static/Dynamic'),
ImportColumn::make('characteristics_type')
->requiredMapping()
->exampleHeader('Characteristics Type')
->label('CHARACTERISTICS TYPE')
->example('ZMM values'),
ImportColumn::make('string_value')
->requiredMapping()
->exampleHeader('String Value')
->label('STRING VALUE')
->example('1'),
ImportColumn::make('string_font')
->requiredMapping()
->exampleHeader('String Font')
->label('STRING FONT')
->example('Arial'),
ImportColumn::make('string_size')
->requiredMapping()
->exampleHeader('String Size')
->label('STRING SIZE')
->example('12'),
ImportColumn::make('element_colour')
->requiredMapping()
->exampleHeader('Element Colour')
->label('ELEMENT COLOUR')
->example('Black'),
ImportColumn::make('string_align')
->requiredMapping()
->exampleHeader('String Align')
->label('STRING ALIGN')
->example('Left/Center/Right'),
ImportColumn::make('string_x_value')
->requiredMapping()
->exampleHeader('String X Value')
->label('STRING X VALUE')
->example('10'),
ImportColumn::make('string_y_value')
->requiredMapping()
->exampleHeader('String Y Value')
->label('STRING Y VALUE')
->example('20'),
ImportColumn::make('shape_name')
->requiredMapping()
->exampleHeader('Shape Name')
->label('SHAPE NAME')
->example('Line/Rectangle/CurvedRectangle'),
ImportColumn::make('shape_pen_size')
->requiredMapping()
->exampleHeader('Shape Pen Size')
->label('SHAPE PEN SIZE')
->example('0.3'),
ImportColumn::make('curve_radius')
->requiredMapping()
->exampleHeader('Curve Radius')
->label('CURVE RADIUS')
->example('3'),
ImportColumn::make('shape_x1_value')
->requiredMapping()
->exampleHeader('Shape X1 Value')
->label('SHAPE X1 VALUE')
->example('10'),
ImportColumn::make('shape_y1_value')
->requiredMapping()
->exampleHeader('Shape Y1 Value')
->label('SHAPE Y1 VALUE')
->example('20'),
ImportColumn::make('shape_x2_value')
->requiredMapping()
->exampleHeader('Shape X2 Value')
->label('SHAPE X2 VALUE')
->example('30'),
ImportColumn::make('shape_y2_value')
->requiredMapping()
->exampleHeader('Shape Y2 Value')
->label('SHAPE Y2 VALUE')
->example('40'),
ImportColumn::make('image_x')
->requiredMapping()
->exampleHeader('Image X')
->label('IMAGE X')
->example('15'),
ImportColumn::make('image_y')
->requiredMapping()
->exampleHeader('Image Y')
->label('IMAGE Y')
->example('25'),
ImportColumn::make('image_width')
->requiredMapping()
->exampleHeader('Image Width')
->label('IMAGE WIDTH')
->example('100'),
ImportColumn::make('image_height')
->requiredMapping()
->exampleHeader('Image Height')
->label('IMAGE HEIGHT')
->example('100'),
ImportColumn::make('qr_value')
->requiredMapping()
->exampleHeader('QR Value')
->label('QR VALUE')
->example('246118|53246735267'),
ImportColumn::make('qr_align')
->requiredMapping()
->exampleHeader('QR Align')
->label('QR ALIGN')
->example('Left/Center/Right'),
ImportColumn::make('qr_size')
->requiredMapping()
->exampleHeader('QR Size')
->label('QR SIZE')
->example('10'),
ImportColumn::make('qr_x_value')
->requiredMapping()
->exampleHeader('QR X Value')
->label('QR X VALUE')
->example('30'),
ImportColumn::make('qr_y_value')
->requiredMapping()
->exampleHeader('QR Y Value')
->label('QR Y VALUE')
->example('40'),
ImportColumn::make('created_by')
->requiredMapping()
->exampleHeader('Created By')
->label('CREATED BY')
->example('RAW001234'),
ImportColumn::make('design_element_type'),
ImportColumn::make('element_id'),
ImportColumn::make('element_type'),
ImportColumn::make('string_value'),
ImportColumn::make('string_font'),
ImportColumn::make('string_size'),
ImportColumn::make('element_colour'),
ImportColumn::make('string_align'),
ImportColumn::make('string_x_value'),
ImportColumn::make('string_y_value'),
ImportColumn::make('shape_name'),
ImportColumn::make('shape_pen_size'),
ImportColumn::make('shape_x1_value'),
ImportColumn::make('shape_y1_value'),
ImportColumn::make('shape_x2_value'),
ImportColumn::make('shape_y2_value'),
ImportColumn::make('image_path'),
ImportColumn::make('image_type'),
ImportColumn::make('image_x'),
ImportColumn::make('image_y'),
ImportColumn::make('image_width'),
ImportColumn::make('image_height'),
ImportColumn::make('qr_value'),
ImportColumn::make('qr_align'),
ImportColumn::make('qr_size'),
ImportColumn::make('qr_x_value'),
ImportColumn::make('qr_y_value'),
ImportColumn::make('created_by'),
ImportColumn::make('updated_by'),
];
}
public function resolveRecord(): ?StickerDetail
{
// return StickerDetail::firstOrNew([
// // Update existing records, matching them by `$this->data['column_name']`
// 'email' => $this->data['email'],
// ]);
$warnMsg = [];
$sticker = $this->data['sticker_structure_detail_id'] ?? null;
$stickerCode = StickerStructureDetail::where('sticker_id', $sticker)->first();
if (!$stickerCode) {
$warnMsg[] = "Sticker Id not found in Sticker Structure Detail";
}
$stickerId = $stickerCode->id;
$user = User::where('name', $this->data['created_by'])->first();
if (!$user) {
$warnMsg[] = "User not found";
}
$designType = strtolower($this->data['design_element_type'] ?? '');
$rules = [
'text' => [
'required' => ['string_x_value', 'string_y_value'],
'allowed' => [
'string_value',
'string_font',
'string_size',
'string_align',
'string_colour',
'string_x_value',
'string_y_value',
],
],
'image' => [
'required' => ['image_x', 'image_y', 'image_width', 'image_height'],
'allowed' => [
'image_x',
'image_y',
'image_width',
'image_height',
],
],
'shape' => [
'required' => ['shape_name', 'shape_pen_size', 'shape_x1_value', 'shape_y1_value', 'shape_x2_value', 'shape_y2_value'],
'allowed' => [
'shape_name',
'shape_pen_size',
'curve_radius',
'shape_x1_value',
'shape_y1_value',
'shape_x2_value',
'shape_y2_value',
],
],
'qr' => [
'required' => ['qr_value', 'qr_x_value', 'qr_y_value', 'qr_size'],
'allowed' => [
'qr_value',
'qr_align',
'qr_size',
'qr_x_value',
'qr_y_value',
],
],
];
if (!isset($rules[$designType])) {
$warnMsg[] = "Invalid Design Element Type: {$designType}";
}
if (isset($rules[$designType])) {
foreach ($rules[$designType]['required'] as $field) {
if (empty($this->data[$field])) {
$warnMsg[] = ucfirst($designType) . " requires {$field}";
}
}
}
$allElementFields = [
'string_value','string_font','string_size','string_align','string_colour',
'string_x_value','string_y_value',
'image_x','image_y','image_width','image_height',
'shape_name','shape_pen_size','curve_radius',
'shape_x1_value','shape_y1_value','shape_x2_value','shape_y2_value',
'qr_value','qr_align','qr_size','qr_x_value','qr_y_value',
];
if (isset($rules[$designType])) {
$allowed = $rules[$designType]['allowed'];
foreach ($allElementFields as $field) {
if (!in_array($field, $allowed, true) && !empty($this->data[$field])) {
$warnMsg[] = "Field {$field} is not allowed for {$designType} element";
}
}
}
if (!empty($warnMsg)) {
throw new RowImportFailedException(implode(' | ', $warnMsg));
}
StickerDetail::Create([
'sticker_structure_detail_id' => $stickerId,
'design_element_type' => $this->data['design_element_type'],
'element_id' => $this->data['element_id'],
'element_type' => $this->data['element_type'],
'characteristics_type' => $this->data['characteristics_type'],
'string_value' => $this->data['string_value'],
'string_font' => $this->data['string_font'],
'string_size' => $this->data['string_size'],
'element_colour' => $this->data['element_colour'],
'string_align' => $this->data['string_align'],
'string_x_value' => $this->data['string_x_value'],
'string_y_value' => $this->data['string_y_value'],
'shape_name' => $this->data['shape_name'],
'shape_pen_size' => $this->data['shape_pen_size'],
'curve_radius' => $this->data['curve_radius'],
'shape_x1_value' => $this->data['shape_x1_value'],
'shape_y1_value' => $this->data['shape_y1_value'],
'shape_x2_value' => $this->data['shape_x2_value'],
'shape_y2_value' => $this->data['shape_y2_value'],
'image_x' => $this->data['image_x'],
'image_y' => $this->data['image_y'],
'image_width' => $this->data['image_width'],
'image_height' => $this->data['image_height'],
'qr_value' => $this->data['qr_value'],
'qr_align' => $this->data['qr_align'],
'qr_size' => $this->data['qr_size'],
'qr_x_value' => $this->data['qr_x_value'],
'qr_y_value' => $this->data['qr_y_value'],
'created_by' => $this->data['created_by'],
]);
return null;
//return new StickerDetail();
return new StickerDetail();
}
public static function getCompletedNotificationBody(Import $import): string

View File

@@ -14,56 +14,43 @@ class StickerMappingMasterImporter extends Importer
public static function getColumns(): array
{
return [
ImportColumn::make('plant_id')
ImportColumn::make('plant')
->requiredMapping()
->numeric()
->rules(['required', 'integer']),
ImportColumn::make('item_id')
->exampleHeader('Plant Name')
->example('Ransar Industries-I')
->label('Plant Name')
->relationship(resolveUsing:'name')
->rules(['required']),
ImportColumn::make('item')
->requiredMapping()
->numeric()
->rules(['required', 'integer']),
ImportColumn::make('sticker1'),
ImportColumn::make('sticker1_machine_id')
->numeric()
->rules(['integer']),
ImportColumn::make('sticker1_print_ip'),
ImportColumn::make('sticker2'),
ImportColumn::make('sticker2_machine_id')
->numeric()
->rules(['integer']),
ImportColumn::make('sticker2_print_ip'),
ImportColumn::make('sticker3'),
ImportColumn::make('sticker3_machine_id')
->numeric()
->rules(['integer']),
ImportColumn::make('sticker3_print_ip'),
ImportColumn::make('sticker4'),
ImportColumn::make('sticker4_machine_id')
->numeric()
->rules(['integer']),
ImportColumn::make('sticker4_print_ip'),
ImportColumn::make('sticker5'),
ImportColumn::make('sticker5_machine_id')
->numeric()
->rules(['integer']),
ImportColumn::make('sticker5_print_ip'),
ImportColumn::make('sticker6'),
ImportColumn::make('sticker6_machine_id')
->numeric()
->rules(['integer']),
ImportColumn::make('sticker6_print_ip'),
ImportColumn::make('sticker7'),
ImportColumn::make('sticker7_machine_id')
->numeric()
->rules(['integer']),
ImportColumn::make('sticker7_print_ip'),
ImportColumn::make('sticker8'),
ImportColumn::make('sticker8_machine_id')
->numeric()
->rules(['integer']),
ImportColumn::make('sticker8_print_ip'),
ImportColumn::make('created_by'),
ImportColumn::make('updated_by'),
->exampleHeader('Item Code')
->example('630987')
->label('Item Code')
->relationship(resolveUsing:'code')
->rules(['required']),
ImportColumn::make('sticker1')
->label('Sticker Label 1')
->exampleHeader('Sticker Label 1')
->example('Label 1')
->rules(['required']),
ImportColumn::make('sticker2')
->label('Sticker Label 2')
->exampleHeader('Sticker Label 2')
->example('601468'),
ImportColumn::make('sticker3')
->label('Sticker Label 3')
->exampleHeader('Sticker Label 3'),
//->example(''),
ImportColumn::make('sticker4')
->label('Sticker Label 4')
->exampleHeader('Sticker Label 4'),
ImportColumn::make('sticker5')
->label('Sticker Label 5')
->exampleHeader('Sticker Label 5'),
ImportColumn::make('created_by')
->label('Created By')
->exampleHeader('Created By'),
// ImportColumn::make('updated_by'),
];
}

View File

@@ -2,15 +2,10 @@
namespace App\Filament\Imports;
use App\Models\Item;
use App\Models\ItemCharacteristic;
use App\Models\Plant;
use App\Models\StickerStructureDetail;
use App\Models\User;
use Filament\Actions\Imports\ImportColumn;
use Filament\Actions\Imports\Importer;
use Filament\Actions\Imports\Models\Import;
use Filament\Actions\Imports\Exceptions\RowImportFailedException;
class StickerStructureDetailImporter extends Importer
{
@@ -19,133 +14,26 @@ class StickerStructureDetailImporter extends Importer
public static function getColumns(): array
{
return [
ImportColumn::make('plant')
->requiredMapping()
->exampleHeader('Plant Code')
->example('1000')
->label('PLANT CODE')
->relationship(resolveUsing: 'code')
->rules(['required']),
ImportColumn::make('item_characteristic_id')
->requiredMapping()
->exampleHeader('Item Code')
->example('123456')
->label('ITEM CODE')
->rules(['required']),
ImportColumn::make('sticker_id')
->requiredMapping()
->exampleHeader('Sticker ID')
->example('123456')
->label('STICKER ID')
->rules(['required']),
ImportColumn::make('sticker_width')
->requiredMapping()
->exampleHeader('Sticker Width')
->example('90')
->label('STICKER WIDTH')
->rules(['required']),
ImportColumn::make('sticker_height')
->requiredMapping()
->exampleHeader('Sticker Height')
->example('90')
->label('STICKER HEIGHT')
->rules(['required']),
ImportColumn::make('sticker_lmargin')
->requiredMapping()
->exampleHeader('Sticker Left Margin')
->example('0')
->label('STICKER LEFT MARGIN')
->rules(['required']),
ImportColumn::make('sticker_rmargin')
->requiredMapping()
->exampleHeader('Sticker Right Margin')
->example('0')
->label('STICKER RIGHT MARGIN')
->rules(['required']),
ImportColumn::make('sticker_tmargin')
->requiredMapping()
->exampleHeader('Sticker Top Margin')
->example('0')
->label('STICKER TOP MARGIN')
->rules(['required']),
ImportColumn::make('sticker_bmargin')
->requiredMapping()
->exampleHeader('Sticker Bottom Margin')
->example('0')
->label('STICKER BOTTOM MARGIN')
->rules(['required']),
ImportColumn::make('created_by')
->requiredMapping()
->exampleHeader('Created By')
->example('RAW001234')
->label('CREATED BY')
->rules(['required']),
ImportColumn::make('sticker_id'),
ImportColumn::make('sticker_width'),
ImportColumn::make('sticker_height'),
ImportColumn::make('sticker_lmargin'),
ImportColumn::make('sticker_rmargin'),
ImportColumn::make('sticker_tmargin'),
ImportColumn::make('sticker_bmargin'),
ImportColumn::make('created_by'),
ImportColumn::make('updated_by'),
];
}
public function resolveRecord(): ?StickerStructureDetail
{
$warnMsg = [];
// return StickerStructureDetail::firstOrNew([
// // Update existing records, matching them by `$this->data['column_name']`
// 'email' => $this->data['email'],
// ]);
$plant = Plant::where('code', $this->data['plant'])->first();
if (!$plant) {
$warnMsg[] = "Plant code not found";
}
// $item = null;
// if ($plant) {
// $item = Item::where('code', $this->data['itemCharacteristic.item'])->where('plant_id', $plant->id)->first();
// }
// if (!$item) {
// $warnMsg[] = "Item not found";
// }
$itemCode = $this->data['item_characteristic_id'] ?? null;
$item = Item::where('code', $itemCode)->first();
if (!$item) {
$warnMsg[] = "Item not found";
}
$itemChar = ItemCharacteristic::where('item_id', $item->id)->first();
if (!$itemChar) {
$warnMsg[] = "Item not found in item characteristic";
}
$user = User::where('name', $this->data['created_by'])->first();
if (!$user) {
$warnMsg[] = "User not found";
}
if (!empty($warnMsg)) {
throw new RowImportFailedException(implode(', ', $warnMsg));
}
else { //if (empty($warnMsg))
$stickerId = StickerStructureDetail::where('sticker_id', $this->data['sticker_id'])
->first();
if ($stickerId) {
throw new RowImportFailedException("Sticker ID already exist!");
}
}
StickerStructureDetail::Create([
'plant_id' => $plant->id,
'item_characteristic_id' => $itemChar->id,
'sticker_id' => $this->data['sticker_id'],
'sticker_width' => $this->data['sticker_width'],
'sticker_height' => $this->data['sticker_height'],
'sticker_lmargin' => $this->data['sticker_lmargin'],
'sticker_rmargin' => $this->data['sticker_rmargin'],
'sticker_tmargin' => $this->data['sticker_tmargin'],
'sticker_bmargin' => $this->data['sticker_bmargin'],
'created_by' => $this->data['created_by'],
]);
return null;
//return new StickerStructureDetail();
return new StickerStructureDetail();
}
public static function getCompletedNotificationBody(Import $import): string

View File

@@ -1,20 +0,0 @@
<?php
namespace App\Filament\Pages;
use Filament\Pages\Page;
class NotificationSettings extends Page
{
protected static ?string $navigationIcon = 'heroicon-o-document-text';
protected static string $view = 'filament.pages.notification-settings';
public static function getScripts(): array
{
return [
asset('js/push.js')
];
}
}

View File

@@ -1,163 +0,0 @@
<?php
namespace App\Filament\Pages;
use App\Models\CustomerPoMaster;
use App\Models\Plant;
use App\Models\ProductionPlan;
use App\Models\WireMasterPacking;
use Filament\Facades\Filament;
use Filament\Pages\Page;
use Filament\Forms\Concerns\InteractsWithForms;
use Filament\Forms\Form;
use Filament\Forms\Components\Section;
use Filament\Forms\Components\Select;
use Filament\Forms\Components\DatePicker;
use Filament\Forms\Components\Grid;
use Filament\Forms\Components\TextInput;
use Filament\Forms\Components\ViewField;
use Filament\Notifications\Notification;
use Filament\Forms\Components\Actions\Action;
use Filament\Forms\Components\Hidden;
class ProductionCalender extends Page
{
protected static ?string $navigationIcon = 'heroicon-o-document-text';
protected static string $view = 'filament.pages.production-calender';
use InteractsWithForms;
protected $listeners = ['setWorkingDays'];
public $pId;
public array $filters = [];
public function setWorkingDays($days = null)
{
$this->form->fill([
'working_days' => $days ?? 0,
]);
}
public function form(Form $form): Form
{
return $form
->statePath('filters')
->schema([
Section::make('')
->schema([
Select::make('plant_id')
->label('Plant')
->reactive()
//->options(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();
})
->columnSpan(['default' => 10, 'sm' => 7])
->required()
->afterStateUpdated(function ($state, callable $set, callable $get) {
$set('working_days', null);
}),
TextInput::make('working_days')
->label('No. of Working Days')
->numeric()
->readOnly()
->columnSpan(['default' => 10, 'sm' => 2])
->required()
->minValue(0)
->maxValue(31)
->placeholder('Enter working days')
->id('working_days'),
Hidden::make('month')
->label('Month')
->id('month'),
Hidden::make('year')
->label('Year')
->id('year'),
Hidden::make('selected_dates')
->label('Selected Dates')
->id('selected_dates'),
ViewField::make('save')
->view('forms.save')
->columnSpan(['default' => 10, 'sm' => 1]),
ViewField::make('calendar')
->view('forms.calendar')
->columnspan(10),
])
->columns(10)
]);
}
public function saveWorkingDays(){
$plantId = $this->filters['plant_id'] ?? null;
$workingDays = $this->filters['working_days'] ?? null;
$month = $this->filters['month'] ?? null;
$year = $this->filters['year'] ?? null;
$dates = $this->filters['selected_dates'] ?? null;
if (!$plantId) {
Notification::make()
->title('Unknown Plant')
->body("Please select a plant first!")
->danger()
->send();
return;
}
else if (!$workingDays) {
Notification::make()
->title('Unknown Working Days')
->body("Working days can't be empty!")
->danger()
->send();
return;
}
else if (!$month) {
Notification::make()
->title('Unknown Month')
->body("month can't be empty!")
->danger()
->send();
return;
}
else if (!$year) {
Notification::make()
->title('Unknown Year')
->body("Year can't be empty!")
->danger()
->send();
return;
}
$updated = ProductionPlan::where('plant_id', $plantId)
->whereMonth('created_at', $month)
->whereYear('created_at', $year)
->update([
'working_days' => $workingDays,
'leave_dates' => $dates,
'updated_at' => now(),
]);
if ($updated) {
Notification::make()
->title('Success')
->body("Working days updated successfully!")
->success()
->send();
} else {
Notification::make()
->title('No Records Updated')
->body("No production plans found for this plant and month.")
->warning()
->send();
}
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -1,173 +0,0 @@
<?php
namespace App\Filament\Pages;
use App\Models\Plant;
use Filament\Facades\Filament;
use Filament\Forms\Components\DatePicker;
use Filament\Pages\Page;
use Filament\Forms\Form;
use Filament\Forms\Components\Section;
use Filament\Forms\Components\Select;
use Filament\Forms\Components\TextInput;
use Filament\Notifications\Notification;
class ProductionTarget extends Page
{
protected static ?string $navigationIcon = 'heroicon-o-document-text';
protected static string $view = 'filament.pages.production-target';
public array $filters = [];
public function form(Form $form): Form
{
return $form
->statePath('filters')
->schema([
Section::make('')
->schema([
Select::make('plant_id')
->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()
->afterStateUpdated(function ($state, callable $get, $set) {
$set('line_id', null);
$set('year', null);
$set('month', null);
$this->dispatch('loadData',$state, '', '', '');
}),
Select::make('line_id')
->label('Line')
->required()
->columnSpan(1)
->options(function (callable $get) {
if (!$get('plant_id')) {
return [];
}
return \App\Models\Line::where('plant_id', $get('plant_id'))
->pluck('name', 'id')
->toArray();
})
->reactive()
->afterStateUpdated(function ($state, callable $get, $set) {
$plantId = $get('plant_id');
$set('year', null);
$set('month', null);
$this->dispatch('loadData',$plantId, $state, '', '');
}),
Select::make('year')
->label('Year')
->reactive()
->options([
'2026' => '2026',
'2027' => '2027',
'2028' => '2028',
'2029' => '2029',
'2030' => '2030',
'2031' => '2031',
'2032' => '2032',
'2033' => '2033',
'2034' => '2034',
'2035' => '2035',
'2036' => '2036',
'2037' => '2037',
'2038' => '2038',
'2039' => '2039',
'2040' => '2040',
])
->required()
->afterStateUpdated(function ($state, callable $get, $set) {
$set('month', null);
$plantId = $get('plant_id');
$lineId = $get('line_id');
$this->dispatch('loadData',$plantId, $lineId, $state, '');
}),
Select::make('month')
->label('Month')
->reactive()
->options([
'01' => 'January',
'02' => 'February',
'03' => 'March',
'04' => 'April',
'05' => 'May',
'06' => 'June',
'07' => 'July',
'08' => 'August',
'09' => 'September',
'10' => 'October',
'11' => 'November',
'12' => 'December',
])
->required()
->afterStateUpdated(function ($state, callable $get) {
$plantId = $get('plant_id');
$lineId = $get('line_id');
// $month = $get('month');
$year = $get('year');
$month = (int) $get('month');
if (!$month) {
return;
}
$this->dispatch('loadData', $plantId, $lineId, $month, $year);
}),
])
->columns(4)
]);
}
public function export(){
$plantId = $this->filters['plant_id'] ?? null;
$lineId = $this->filters['line_id'] ?? null;
$year = $this->filters['year'] ?? null;
$month = $this->filters['month'] ?? null;
if (! $plantId) {
Notification::make()
->title('Plant')
->body("please select plant to export data..!")
->danger()
->send();
return;
}
else if (! $lineId) {
Notification::make()
->title('Line')
->body("please select line to export data..!")
->danger()
->send();
return;
}
else if (! $year) {
Notification::make()
->title('Year')
->body("please select year to export data..!")
->danger()
->send();
return;
}
else if (! $month) {
Notification::make()
->title('Month')
->body("please select month to export data..!")
->danger()
->send();
return;
}
$this->dispatch('loadData1' ,$plantId, $lineId, $year, $month);
}
}

View File

@@ -1,163 +0,0 @@
<?php
namespace App\Filament\Pages;
use Filament\Pages\Page;
use Filament\Forms\Components\Select;
use Filament\Forms\Components\TextInput;
use Filament\Forms\Form;
use Filament\Pages\Dashboard\Concerns\HasFiltersForm;
use Filament\Tables\Filters\SelectFilter;
use Illuminate\Support\Facades\DB;
use App\Models\Plant;
use App\Models\RequestQuotation;
use App\Models\RfqTransporterBid;
use Filament\Facades\Filament;
use Filament\Widgets\Widget;
use Illuminate\Support\Facades\Auth;
use Filament\Forms\Components\Section;
use Filament\Forms;
use Filament\Forms\Concerns\InteractsWithForms;
use Filament\Forms\Contracts\HasForms;
class RfqDashboard extends Page
{
protected static ?string $navigationIcon = 'heroicon-o-document-text';
protected static string $view = 'filament.pages.rfq-dashboard';
protected static ?string $navigationGroup = 'RFQ Dashboard';
use HasFiltersForm;
public function mount(): void
{
session()->forget(['transport_name']);
session()->forget(['rfq_number']);
$this->filtersForm->fill([
'transport_name' => null,
'rfq_number' => null
]);
}
public function filtersForm(Form $form): Form
{
return $form
->statePath('filters')
->schema([
Section::make('')
->schema([
// Select::make('plant')
// ->label('Select 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();
// })
// ->afterStateUpdated(function ($state,callable $set) {
// session(['selected_plant' => $state]);
// // $set('rfq_number', null);
// session()->forget('rfq_number');
// }),
Select::make('rfq_number')
->label('Select RFQ Number')
->reactive()
->options(function (callable $get) {
return RequestQuotation::orderBy('rfq_number')
->pluck('rfq_number', 'id')
->toArray();
})
->afterStateUpdated(function ($state, callable $set) {
session(['rfq_id' => $state]);
$set('transport_name', null);
session()->forget('transport_name');
}),
Select::make('transport_name')
->label('User name')
->reactive()
->options(function (callable $get) {
$rfqId = $get('rfq_number');
if (!$rfqId) {
return [];
}
$user = Filament::auth()->user();
if ($user->hasRole(['Super Admin', 'Rfq Supervisor'])) {
return RfqTransporterBid::query()
->where('request_quotation_id', $rfqId)
->whereNotNull('transporter_name')
->distinct()
->pluck('transporter_name', 'transporter_name')
->toArray();
}
return RfqTransporterBid::query()
->where('request_quotation_id', $rfqId)
->where('transporter_name', $user->name)
->distinct()
->pluck('transporter_name', 'transporter_name')
->toArray();
})
->afterStateUpdated(function ($state, callable $set) {
session(['transport_name' => $state]);
}),
// Select::make('transport_name')
// ->label('User name')
// ->reactive()
// ->options(function () {
// $user = Filament::auth()->user();
// if ($user->hasRole(['Super Admin', 'Rfq Supervisor'])) {
// return RfqTransporterBid::query()
// ->whereNotNull('transporter_name')
// ->distinct()
// ->pluck('transporter_name', 'transporter_name')
// ->toArray();
// }
// return RfqTransporterBid::query()
// ->where('transporter_name', $user->name)
// ->distinct()
// ->pluck('transporter_name', 'transporter_name')
// ->toArray();
// })
// ->afterStateUpdated(function ($state, callable $set) {
// session(['transport_name' => $state]);
// $set('rfq_number', null);
// session()->forget('rfq_number');
// }),
// Select::make('rfq_number')
// ->label('Select RFQ Number')
// ->reactive()
// ->options(function (callable $get) {
// $transportName = $get('transport_name');
// if (!$transportName) {
// return [];
// }
// return RequestQuotation::where('transporter_name', $transportName)
// ->pluck('rfq_number', 'rfq_number')
// ->toArray();
// })
// ->afterStateUpdated(function ($state) {
// session(['rfq_number' => $state]);
// }),
])
->columns(2),
]);
}
public static function canAccess(): bool
{
return Auth::check() && Auth::user()->can('view rfq dashboard');
}
}

View File

@@ -1,58 +0,0 @@
<?php
namespace App\Filament\Pages;
use App\Models\RequestQuotation;
use Filament\Pages\Page;
use Filament\Forms\Components\Section;
use Filament\Forms\Components\Select;
use Filament\Forms\Form;
use Filament\Pages\Dashboard\Concerns\HasFiltersForm;
use Illuminate\Support\Facades\Auth;
class RfqOverview extends Page
{
protected static ?string $navigationIcon = 'heroicon-o-document-text';
protected static string $view = 'filament.pages.rfq-overview';
protected static ?string $navigationGroup = 'RFQ Dashboard';
use HasFiltersForm;
public function mount(): void
{
session()->forget(['rfq_id']);
$this->filtersForm->fill([
'rfq_id' => null
]);
}
public function filtersForm(Form $form): Form
{
return $form
->statePath('filters')
->schema([
Section::make('')
->schema([
Select::make('rfq_number')
->label('Select RFQ Number')
->reactive()
->options(function (callable $get) {
return RequestQuotation::orderBy('rfq_number')
->pluck('rfq_number', 'id')
->toArray();
})
->afterStateUpdated(function ($state, callable $set) {
session(['rfq_id' => $state]);
}),
])
->columns(1),
]);
}
public static function canAccess(): bool
{
return Auth::check() && Auth::user()->can('view rfq overview dashboard');
}
}

View File

@@ -1,240 +0,0 @@
<?php
namespace App\Filament\Pages;
use App\Models\Item;
use App\Models\ItemCharacteristic;
use App\Models\Plant;
use App\Models\StickerDetail;
use App\Models\StickerStructureDetail;
use App\Services\StickerPdfService;
use Filament\Facades\Filament;
use Filament\Forms\Components\Section;
use Filament\Forms\Components\Select;
use Filament\Forms\Components\ViewField;
use Filament\Forms\Form;
use Filament\Forms\Get;
use Filament\Notifications\Notification;
use Filament\Pages\Dashboard\Concerns\HasFiltersForm;
use Filament\Pages\Page;
use Illuminate\Support\Facades\Auth;
class StickerStructurePreviewPage extends Page
{
use HasFiltersForm;
protected static ?string $navigationIcon = 'heroicon-o-document-text';
protected static string $view = 'filament.pages.sticker-structure-preview-page';
protected static ?string $navigationGroup = 'Customized Sticker Printing';
public $stickerId;
public $plantId;
public $itemId;
public ?string $pdfPreview = null;
// public array $filters = [];
public function mount(): void
{
session()->forget(['stick_id', 'selected_plant', 'selected_item']);
$this->form->fill([
'sticker_id' => null,
'plant' => null,
'item' => null,
]);
}
public function form(Form $form): Form
{
return $form
->statePath('filters') // Store form state in 'filters'
->schema([
Section::make('')
->schema([
Select::make('sticker_id')
->label('Sticker ID')
->nullable()
->options(function (callable $get) {
return StickerStructureDetail::orderByDesc('id')->pluck('sticker_id', 'sticker_id')->toArray();
})
->afterStateUpdated(callback: function ($state, callable $set) {
session(['stick_id' => $state]);
$set('plant', null);
$set('item', null);
$this->pdfPreview = null;
})
->searchable()
->reactive()
->required(),
Select::make('plant')
->label('Select Plant')
->reactive()
// ->options(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();
})
->afterStateUpdated(function ($state, callable $set) {
session(['stick_id' => $state]);
session(['selected_plant' => $state]);
$set('item', null);
session()->forget('item');
$this->pdfPreview = null;
}),
Select::make('item')
->label('Search by Item Code')
->nullable()
->options(function (callable $get) {
$plant = $get('plant');
return $plant ? ItemCharacteristic::where('plant_id', $plant)->with('item')->get()->pluck('item.code', 'id')->toArray() : []; // ->orderBy('plant_id')
})
->afterStateUpdated(function ($state, callable $set) {
session(['stick_id' => $state]);
session(['selected_plant' => $state]);
session(['selected_item' => $state]);
$this->pdfPreview = null;
// $set('item_id', null);
// session()->forget('item');
})
->searchable()
->reactive(),
// ViewField::make('generate_template')
// ->view('fields.generate-template-preview')
// ->reactive()
// // ->key(fn ($get) => 'generate-template' . ($get('sticker_id_live') ?? 'empty'))
// ->key(fn (Get $get) => 'generate-template-'.
// ($get('sticker_id') ?? 'empty').'-'.
// ($get('plant') ?? 'empty').'-'.
// ($get('item_characteristic_id') ?? 'empty')
// )
// // ->viewData(fn (Get $get) => [
// // 'sticker_id' => $get('sticker_id_live') ?? 'empty',
// // ]),
// ->viewData(fn (Get $get) => [
// 'sticker_id' => $get('sticker_id') ?? 'empty',
// 'plant_id' => $get('plant') ?? 'empty',
// 'item_characteristic_id' => $get('item') ?? 'empty',
// ])
// ->hidden(fn (callable $get) => ($get('sticker_id') == null || $get('sticker_id') == '0' || empty($get('sticker_id'))) || (($get('plant') != null || $get('plant') != '') &&
// ($get('item') == null || $get('item') == '' || empty($get('item'))))),
])
->columns(3),
]);
}
public function showPreview()
{
$state = $this->form->getState();
$stickerId = trim($state['sticker_id'] ?? '') ?: null;
// $stickerId = $this->form->getState()['sticker_id'];
// $stickerId = trim($stickerId) ?? null;
$this->stickerId = $stickerId;
$plantId = trim($state['plant'] ?? '') ?: null;
// $plantId = $this->form->getState()['plant'];
// $plantId = trim($plantId) ?? null;
$this->plantId = $plantId;
$itemId = trim($state['item'] ?? '') ?: null;
// $itemId = $this->form->getState()['item'];
// $itemId = trim($itemId) ?? null;
$this->itemId = $itemId;
$this->pdfPreview = null;
// $operatorName = Filament::auth()->user()->name;
if (! $stickerId) {
Notification::make()->title('Please select a Sticker ID first!')->danger()->duration(2000)->send();
$this->form->fill([
'sticker_id' => $stickerId ?? null,
'plant' => $plantId ?? null,
'item' => $itemId ?? null,
]);
return;
} elseif ($plantId && ! $itemId) {
Notification::make()->title('Please select an Item Code!')->danger()->duration(2000)->send();
$this->form->fill([
'sticker_id' => $stickerId,
'plant' => $plantId ?? null,
'item' => $itemId ?? null,
]);
return;
} elseif ($stickerId && $plantId && $itemId != null && $itemId != '') {
$itemCharacteristic = $itemId ? ItemCharacteristic::find($itemId) : null;
$structure = StickerStructureDetail::where('sticker_id', $stickerId)->first();
if (! $structure) {
Notification::make()->title('Sticker structure not found!')->danger()->send();
return;
}
$dynamicElements = StickerDetail::where('sticker_structure_detail_id', $structure->id)->get();
try {
$stickerPdfService = new StickerPdfService;
$this->pdfPreview = $stickerPdfService->generateStickerItem($stickerId, $dynamicElements, $itemCharacteristic);
Notification::make()
->title('Sticker Preview Generated!')
->success()
->duration(2000)
->send();
} catch (\Exception $e) {
Notification::make()
->title('Error generating sticker preview!')
->body($e->getMessage())
->danger()
->send();
}
} else {
$elements = StickerStructureDetail::where('sticker_id', $stickerId)->first();
try {
$stickerPdfService = new StickerPdfService;
$this->pdfPreview = $stickerPdfService->generateSticker($stickerId, $elements->toArray());
Notification::make()
->title('Sticker Preview Generated!')
->success()
->duration(2000)
->send();
} catch (\Exception $e) {
Notification::make()
->title('Error generating sticker preview!')
->body($e->getMessage())
->danger()
->send();
}
}
}
public static function getNavigationLabel(): string
{
return 'Sticker Structure Preview';
}
public function getHeading(): string
{
return 'Sticker Structure Preview';
}
public static function canAccess(): bool
{
return Auth::check() && Auth::user()->can('view sticker structure preview');
}
}

View File

@@ -1,17 +0,0 @@
<?php
namespace App\Filament\Pages;
use Filament\Pages\Page;
class Welcome extends Page
{
protected static ?string $navigationIcon = 'heroicon-o-document-text';
protected static string $view = 'filament.pages.welcome';
public function getHeading(): string
{
return '';
}
}

View File

@@ -1,217 +0,0 @@
<?php
namespace App\Filament\Resources;
use App\Filament\Exports\EmployeeMasterExporter;
use App\Filament\Imports\EmployeeMasterImporter;
use App\Filament\Resources\EmployeeMasterResource\Pages;
use App\Filament\Resources\EmployeeMasterResource\RelationManagers;
use App\Models\EmployeeMaster;
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\Tables\Actions\ExportAction;
use Filament\Tables\Actions\ImportAction;
use Illuminate\Validation\Rule;
class EmployeeMasterResource extends Resource
{
protected static ?string $model = EmployeeMaster::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')
->relationship('plant', 'name')
->required(),
Forms\Components\TextInput::make('name')
->label('Name')
->required()
->reactive()
->extraInputAttributes([
'oninput' => 'this.value = this.value.replace(/[^a-zA-Z\s]/g, "")',
]),
Forms\Components\TextInput::make('code')
->label('ID')
->extraInputAttributes([
'oninput' => 'this.value = this.value.replace(/[^a-zA-Z0-9]/g, "")',])
->required()
->unique(
table: 'employee_masters',
column: 'code',
ignoreRecord: true
)
->validationMessages([
'unique' => 'Duplicate employee code already exists.',
]),
Forms\Components\TextInput::make('department')
->label('Department')
->required(),
Forms\Components\TextInput::make('designation')
->label('Designation')
->extraInputAttributes([
'oninput' => 'this.value = this.value.replace(/[^a-zA-Z\s]/g, "")',])
->required(),
Forms\Components\TextInput::make('email')
->label('Email')
->email()
->required(),
Forms\Components\TextInput::make('mobile_number')
->label('Mobile Number')
->length(10)
->reactive()
->extraInputAttributes([
'oninput' => 'this.value = this.value.replace(/[^0-9]/g, "").slice(0, 10)', // blocks non-numbers + limits to 10 chars
'maxlength' => 10,
])
->required()
->unique(
table: 'employee_masters',
column: 'mobile_number',
ignoreRecord: true
)
->validationMessages([
'unique' => 'Duplicate mobile number already exists.',
]),
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.')
->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;
})
->alignCenter(),
Tables\Columns\TextColumn::make('plant.name')
->numeric()
->sortable()
->alignCenter(),
Tables\Columns\TextColumn::make('name')
->label('Name')
->sortable()
->alignCenter()
->searchable(),
Tables\Columns\TextColumn::make('code')
->label('Employee ID')
->sortable()
->alignCenter()
->searchable(),
Tables\Columns\TextColumn::make('department')
->label('Department')
->sortable()
->alignCenter()
->searchable(),
Tables\Columns\TextColumn::make('designation')
->label('Designation')
->sortable()
->alignCenter()
->searchable(),
Tables\Columns\TextColumn::make('email')
->label('Email')
->sortable()
->alignCenter()
->searchable(),
Tables\Columns\TextColumn::make('mobile_number')
->label('Mobile Number')
->sortable()
->alignCenter()
->searchable(),
Tables\Columns\TextColumn::make('created_at')
->dateTime()
->sortable()
->alignCenter(),
Tables\Columns\TextColumn::make('updated_at')
->dateTime()
->sortable()
->toggleable(isToggledHiddenByDefault: true)
->alignCenter(),
Tables\Columns\TextColumn::make('created_by')
->label('Created by')
->sortable()
->alignCenter(),
Tables\Columns\TextColumn::make('updated_by')
->label('Updated by')
->sortable()
->toggleable(isToggledHiddenByDefault: true)
->alignCenter(),
Tables\Columns\TextColumn::make('deleted_at')
->dateTime()
->sortable()
->toggleable(isToggledHiddenByDefault: true)
->alignCenter(),
])
->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()
->importer(EmployeeMasterImporter::class)
->visible(function() {
return Filament::auth()->user()->can('view import employee master');
}),
ExportAction::make()
->exporter(EmployeeMasterExporter::class)
->visible(function() {
return Filament::auth()->user()->can('view export employee master');
}),
]);
}
public static function getRelations(): array
{
return [
//
];
}
public static function getPages(): array
{
return [
'index' => Pages\ListEmployeeMasters::route('/'),
'create' => Pages\CreateEmployeeMaster::route('/create'),
'view' => Pages\ViewEmployeeMaster::route('/{record}'),
'edit' => Pages\EditEmployeeMaster::route('/{record}/edit'),
];
}
public static function getEloquentQuery(): Builder
{
return parent::getEloquentQuery()
->withoutGlobalScopes([
SoftDeletingScope::class,
]);
}
}

View File

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

View File

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

View File

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

View File

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

View File

@@ -10,7 +10,6 @@ use App\Models\InvoiceValidation;
use App\Models\Item;
use App\Models\Plant;
use App\Models\StickerMaster;
use App\Notifications\PushAlertNotification;
use Filament\Facades\Filament;
use Filament\Notifications\Notification;
use Filament\Pages\Concerns\ExposesTableToWidgets;
@@ -137,10 +136,6 @@ class CreateInvoiceValidation extends CreateRecord
->send();
$this->dispatch('playNotificationSound');
$user1 = Filament::auth()->user();
$user1->notify(new PushAlertNotification());
$this->form->fill([
'plant_id' => $plantId,
'invoice_number' => $invoiceNumber,
@@ -2290,7 +2285,6 @@ class CreateInvoiceValidation extends CreateRecord
->danger()
->seconds(3)
->send();
$this->dispatch('playWarnSound');
$this->form->fill([

View File

@@ -1,955 +0,0 @@
<?php
namespace App\Filament\Resources;
use App\Filament\Resources\ItemCharacteristicResource\Pages;
use App\Filament\Resources\ItemCharacteristicResource\RelationManagers;
use App\Models\Item;
use App\Models\ItemCharacteristic;
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;
class ItemCharacteristicResource extends Resource
{
protected static ?string $model = ItemCharacteristic::class;
protected static ?string $navigationIcon = 'heroicon-o-rectangle-stack';
protected static ?string $navigationGroup = 'Customized Sticker Printing';
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('class')
->label('Class'),
Forms\Components\TextInput::make('zz1_cn_bill_ord')
->label('ZZ1 CN Bill Ord'),
Forms\Components\TextInput::make('zmm_amps')
->label('ZMM Amps'),
Forms\Components\TextInput::make('zmm_brand')
->label('ZMM Brand'),
Forms\Components\TextInput::make('zmm_degreeofprotection')
->label('ZMM Degree of Protection'),
Forms\Components\TextInput::make('zmm_delivery')
->label('ZMM Delivery'),
Forms\Components\TextInput::make('zmm_dir_rot')
->label('ZMM Direction Rotation'),
Forms\Components\TextInput::make('zmm_discharge')
->label('ZMM Discharge'),
Forms\Components\TextInput::make('zmm_discharge_max')
->label('ZMM Discharge Max'),
Forms\Components\TextInput::make('zmm_discharge_min')
->label('ZMM Discharge Min'),
Forms\Components\TextInput::make('zmm_duty')
->label('ZMM Duty'),
Forms\Components\TextInput::make('zmm_eff_motor')
->label('ZMM Eff Motor'),
Forms\Components\TextInput::make('zmm_eff_pump')
->label('ZMM Eff Pump'),
Forms\Components\TextInput::make('zmm_frequency')
->label('ZMM Frequency'),
Forms\Components\TextInput::make('zmm_head')
->label('ZMM Head'),
Forms\Components\TextInput::make('zmm_heading')
->label('ZMM Heading'),
Forms\Components\TextInput::make('zmm_head_max')
->label('ZMM Head Max'),
Forms\Components\TextInput::make('zmm_head_minimum')
->label('ZMM Head Minimum'),
Forms\Components\TextInput::make('zmm_idx_eff_mtr')
->label('ZMM Idx Eff Mtr'),
Forms\Components\TextInput::make('zmm_idx_eff_pump')
->label('ZMM Idx Eff Pump'),
Forms\Components\TextInput::make('zmm_kvacode')
->label('ZMM KVACode'),
Forms\Components\TextInput::make('zmm_maxambtemp')
->label('ZMM Max Amb Temp'),
Forms\Components\TextInput::make('zmm_mincoolingflow')
->label('ZMM Min Cooling Flow'),
Forms\Components\TextInput::make('zmm_motorseries')
->label('ZMM Motor Series'),
Forms\Components\TextInput::make('zmm_motor_model')
->label('ZMM Motor Model'),
Forms\Components\TextInput::make('zmm_outlet')
->label('ZMM Outlet'),
Forms\Components\TextInput::make('zmm_phase')
->label('ZMM Phase'),
Forms\Components\TextInput::make('zmm_pressure')
->label('ZMM Pressure'),
Forms\Components\TextInput::make('zmm_pumpflowtype')
->label('ZMM Pump Flow Type'),
Forms\Components\TextInput::make('zmm_pumpseries')
->label('ZMM Pump Series'),
Forms\Components\TextInput::make('zmm_pump_model')
->label('ZMM Pump Model'),
Forms\Components\TextInput::make('zmm_ratedpower')
->label('ZMM Rated Power'),
Forms\Components\TextInput::make('zmm_region')
->label('ZMM Region'),
Forms\Components\TextInput::make('zmm_servicefactor')
->label('ZMM Service Factor'),
Forms\Components\TextInput::make('zmm_servicefactormaximumamps')
->label('ZMM Service Factor Maximum Amps'),
Forms\Components\TextInput::make('zmm_speed')
->label('ZMM Speed'),
Forms\Components\TextInput::make('zmm_suction')
->label('ZMM Suction'),
Forms\Components\TextInput::make('zmm_suctionxdelivery')
->label('ZMM Suction X Delivery'),
Forms\Components\TextInput::make('zmm_supplysource')
->label('ZMM Supply Source'),
Forms\Components\TextInput::make('zmm_temperature')
->label('ZMM Temperature'),
Forms\Components\TextInput::make('zmm_thrustload')
->label('ZMM Thrust Load'),
Forms\Components\TextInput::make('zmm_volts')
->label('ZMM Volts'),
Forms\Components\TextInput::make('zmm_wire')
->label('ZMM Wire'),
Forms\Components\TextInput::make('zmm_package')
->label('ZMM Package'),
Forms\Components\TextInput::make('zmm_pvarrayrating')
->label('ZMM PV Array Rating'),
Forms\Components\TextInput::make('zmm_isi')
->label('ZMM ISI'),
Forms\Components\TextInput::make('zmm_isimotor')
->label('ZMM ISI Motor'),
Forms\Components\TextInput::make('zmm_isipump')
->label('ZMM ISI Pump'),
Forms\Components\TextInput::make('zmm_isipumpset')
->label('ZMM ISI Pump Set'),
Forms\Components\TextInput::make('zmm_pumpset_model')
->label('ZMM Pump Set Model'),
Forms\Components\TextInput::make('zmm_stages')
->label('ZMM Stages'),
Forms\Components\TextInput::make('zmm_headrange')
->label('ZMM Head Range'),
Forms\Components\TextInput::make('zmm_overall_efficiency')
->label('ZMM Overall Efficiency'),
Forms\Components\TextInput::make('zmm_connection')
->label('ZMM Connection'),
Forms\Components\TextInput::make('zmm_min_bore_size')
->label('ZMM Min Bore Size'),
Forms\Components\TextInput::make('zmm_isireference')
->label('ZMM ISI Reference'),
Forms\Components\TextInput::make('zmm_category')
->label('ZMM Category'),
Forms\Components\TextInput::make('zmm_submergence')
->label('ZMM Submergence'),
Forms\Components\TextInput::make('zmm_capacitorstart')
->label('ZMM Capacitor Start'),
Forms\Components\TextInput::make('zmm_capacitorrun')
->label('ZMM Capacitor Run'),
Forms\Components\TextInput::make('zmm_inch')
->label('ZMM Inch'),
Forms\Components\TextInput::make('zmm_motor_type')
->label('ZMM Motor Type'),
Forms\Components\TextInput::make('zmm_dismantle_direction')
->label('ZMM Dismantle Direction'),
Forms\Components\TextInput::make('zmm_eff_ovrall')
->label('ZMM Overall Efficiency'),
Forms\Components\TextInput::make('zmm_bodymoc')
->label('ZMM Body MOC'),
Forms\Components\TextInput::make('zmm_rotormoc')
->label('ZMM Rotor MOC'),
Forms\Components\TextInput::make('zmm_dlwl')
->label('ZMM DLWL'),
Forms\Components\TextInput::make('zmm_inputpower')
->label('ZMM Input Power'),
Forms\Components\TextInput::make('zmm_imp_od')
->label('ZMM Imp OD'),
Forms\Components\TextInput::make('zmm_ambtemp')
->label('ZMM Ambient Temperature'),
Forms\Components\TextInput::make('zmm_de')
->label('ZMM DE'),
Forms\Components\TextInput::make('zmm_dischargerange')
->label('ZMM Discharge Range'),
Forms\Components\TextInput::make('zmm_efficiency_class')
->label('ZMM Efficiency Class'),
Forms\Components\TextInput::make('zmm_framesize')
->label('ZMM Frame Size'),
Forms\Components\TextInput::make('zmm_impellerdiameter')
->label('ZMM Impeller Diameter'),
Forms\Components\TextInput::make('zmm_insulationclass')
->label('ZMM Insulation Class'),
Forms\Components\TextInput::make('zmm_maxflow')
->label('ZMM Max Flow'),
Forms\Components\TextInput::make('zmm_minhead')
->label('ZMM Min Head'),
Forms\Components\TextInput::make('zmm_mtrlofconst')
->label('ZMM Motor Load Constant'),
Forms\Components\TextInput::make('zmm_nde')
->label('ZMM NDE'),
Forms\Components\TextInput::make('zmm_powerfactor')
->label('ZMM Power Factor'),
Forms\Components\TextInput::make('zmm_tagno')
->label('ZMM Tag No'),
Forms\Components\TextInput::make('zmm_year')
->label('ZMM Year'),
Forms\Components\TextInput::make('zmm_laser_name')
->label('ZMM Laser Name'),
Forms\Components\TextInput::make('zmm_beenote')
->label('ZMM Bee Note'),
Forms\Components\TextInput::make('zmm_beenumber')
->label('ZMM Bee Number'),
Forms\Components\TextInput::make('zmm_beestar')
->label('ZMM Bee Star'),
Forms\Components\TextInput::make('zmm_logo_ce')
->label('ZMM Logo CE'),
Forms\Components\TextInput::make('zmm_codeclass')
->label('ZMM Code Class'),
Forms\Components\TextInput::make('zmm_colour')
->label('ZMM Colour'),
Forms\Components\TextInput::make('zmm_logo_cp')
->label('ZMM Logo CP'),
Forms\Components\TextInput::make('zmm_grade')
->label('ZMM Grade'),
Forms\Components\TextInput::make('zmm_grwt_pset')
->label('ZMM Grwt Pset'),
Forms\Components\TextInput::make('zmm_grwt_cable')
->label('ZMM Grwt Cable'),
Forms\Components\TextInput::make('zmm_grwt_motor')
->label('ZMM Grwt Motor'),
Forms\Components\TextInput::make('zmm_grwt_pf')
->label('ZMM Grwt PF'),
Forms\Components\TextInput::make('zmm_grwt_pump')
->label('ZMM Grwt Pump'),
Forms\Components\TextInput::make('zmm_isivalve')
->label('ZMM ISIV Alve'),
Forms\Components\TextInput::make('zmm_isi_wc')
->label('ZMM ISIV WC'),
Forms\Components\TextInput::make('zmm_labelperiod')
->label('ZMM Label Period'),
Forms\Components\TextInput::make('zmm_length')
->label('ZMM Length'),
Forms\Components\TextInput::make('zmm_license_cml_no')
->label('ZMM License CML No'),
Forms\Components\TextInput::make('zmm_mfgmonyr')
->label('ZMM Mfg Mon Yr'),
Forms\Components\TextInput::make('zmm_modelyear')
->label('ZMM Model Year'),
Forms\Components\TextInput::make('zmm_motoridentification')
->label('ZMM Motor Identification'),
Forms\Components\TextInput::make('zmm_newt_pset')
->label('ZMM Newt Pset'),
Forms\Components\TextInput::make('zmm_newt_cable')
->label('ZMM Newt Cable'),
Forms\Components\TextInput::make('zmm_newt_motor')
->label('ZMM Newt Motor'),
Forms\Components\TextInput::make('zmm_newt_pf')
->label('ZMM Newt PF'),
Forms\Components\TextInput::make('zmm_newt_pump')
->label('ZMM Newt Pump'),
Forms\Components\TextInput::make('zmm_logo_nsf')
->label('ZMM Logo NSF'),
Forms\Components\TextInput::make('zmm_packtype')
->label('ZMM Pack Type'),
Forms\Components\TextInput::make('zmm_panel')
->label('ZMM Panel'),
Forms\Components\TextInput::make('zmm_performance_factor')
->label('ZMM Performance Factor'),
Forms\Components\TextInput::make('zmm_pumpidentification')
->label('ZMM Pump Identification'),
Forms\Components\TextInput::make('zmm_psettype')
->label('ZMM Pset Type'),
Forms\Components\TextInput::make('zmm_size')
->label('ZMM Size'),
Forms\Components\TextInput::make('zmm_eff_ttl')
->label('ZMM Eff TTL'),
Forms\Components\TextInput::make('zmm_type')
->label('ZMM Type'),
Forms\Components\TextInput::make('zmm_usp')
->label('ZMM USP'),
Forms\Components\TextInput::make('zmm_1')
->label('ZMM 1'),
Forms\Components\TextInput::make('zmm_2')
->label('ZMM 2'),
Forms\Components\TextInput::make('zmm_3')
->label('ZMM 3'),
Forms\Components\TextInput::make('zmm_4')
->label('ZMM 4'),
Forms\Components\TextInput::make('zmm_5')
->label('ZMM 5'),
Forms\Components\TextInput::make('zmm_6')
->label('ZMM 6'),
Forms\Components\TextInput::make('zmm_7')
->label('ZMM 7'),
Forms\Components\TextInput::make('zmm_8')
->label('ZMM 8'),
Forms\Components\TextInput::make('zmm_9')
->label('ZMM 9'),
Forms\Components\TextInput::make('zmm_10')
->label('ZMM 10'),
Forms\Components\TextInput::make('zmm_11')
->label('ZMM 11'),
Forms\Components\TextInput::make('zmm_12')
->label('ZMM 12'),
Forms\Components\TextInput::make('zmm_13')
->label('ZMM 13'),
Forms\Components\TextInput::make('zmm_14')
->label('ZMM 14'),
Forms\Components\TextInput::make('zmm_15')
->label('ZMM 15'),
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('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('plant.name')
->label('Plant')
->alignCenter()
->sortable(),
Tables\Columns\TextColumn::make('item.code')
->label('Item Code')
->alignCenter()
->sortable(),
Tables\Columns\TextColumn::make('class')
->label('Class')
->alignCenter()
->sortable(),
Tables\Columns\TextColumn::make('zz1_cn_bill_ord')
->label('ZZ1 CN Bill Ord')
->alignCenter()
->sortable(),
Tables\Columns\TextColumn::make('zmm_amps')
->label('ZMM Amps')
->alignCenter()
->sortable(),
Tables\Columns\TextColumn::make('zmm_brand')
->label('ZMM Brand')
->alignCenter()
->sortable(),
Tables\Columns\TextColumn::make('zmm_degreeofprotection')
->label('ZMM Degree of Protection')
->alignCenter()
->sortable(),
Tables\Columns\TextColumn::make('zmm_delivery')
->label('ZMM Delivery')
->alignCenter()
->sortable(),
Tables\Columns\TextColumn::make('zmm_dir_rot')
->label('ZMM Direction Rotation')
->alignCenter()
->sortable(),
Tables\Columns\TextColumn::make('zmm_discharge')
->label('ZMM Discharge')
->alignCenter()
->sortable(),
Tables\Columns\TextColumn::make('zmm_discharge_max')
->label('ZMM Discharge Max')
->alignCenter()
->sortable(),
Tables\Columns\TextColumn::make('zmm_discharge_min')
->label('ZMM Discharge Min')
->alignCenter()
->sortable(),
Tables\Columns\TextColumn::make('zmm_duty')
->label('ZMM Duty')
->alignCenter()
->sortable(),
Tables\Columns\TextColumn::make('zmm_eff_motor')
->label('ZMM Eff Motor')
->alignCenter()
->sortable(),
Tables\Columns\TextColumn::make('zmm_eff_pump')
->label('ZMM Eff Pump')
->alignCenter()
->sortable(),
Tables\Columns\TextColumn::make('zmm_frequency')
->label('ZMM Frequency')
->alignCenter()
->sortable(),
Tables\Columns\TextColumn::make('zmm_head')
->label('ZMM Head')
->alignCenter()
->sortable(),
Tables\Columns\TextColumn::make('zmm_heading')
->label('ZMM Heading')
->alignCenter()
->sortable(),
Tables\Columns\TextColumn::make('zmm_head_max')
->label('ZMM Head Max')
->alignCenter()
->sortable(),
Tables\Columns\TextColumn::make('zmm_head_minimum')
->label('ZMM Head Minimum')
->alignCenter()
->sortable(),
Tables\Columns\TextColumn::make('zmm_idx_eff_mtr')
->label('ZMM Idx Eff Mtr')
->alignCenter()
->sortable(),
Tables\Columns\TextColumn::make('zmm_idx_eff_pump')
->label('ZMM Idx Eff Pump')
->alignCenter()
->sortable(),
Tables\Columns\TextColumn::make('zmm_kvacode')
->label('ZMM KVACode')
->alignCenter()
->sortable(),
Tables\Columns\TextColumn::make('zmm_maxambtemp')
->label('ZMM Max Amb Temp')
->alignCenter()
->sortable(),
Tables\Columns\TextColumn::make('zmm_mincoolingflow')
->label('ZMM Min Cooling Flow')
->alignCenter()
->sortable(),
Tables\Columns\TextColumn::make('zmm_motorseries')
->label('ZMM Motor Series')
->alignCenter()
->sortable(),
Tables\Columns\TextColumn::make('zmm_motor_model')
->label('ZMM Motor Model')
->alignCenter()
->sortable(),
Tables\Columns\TextColumn::make('zmm_outlet')
->label('ZMM Outlet')
->alignCenter()
->sortable(),
Tables\Columns\TextColumn::make('zmm_phase')
->label('ZMM Phase')
->alignCenter()
->sortable(),
Tables\Columns\TextColumn::make('zmm_pressure')
->label('ZMM Pressure')
->alignCenter()
->sortable(),
Tables\Columns\TextColumn::make('zmm_pumpflowtype')
->label('ZMM Pump Flow Type')
->alignCenter()
->sortable(),
Tables\Columns\TextColumn::make('zmm_pumpseries')
->label('ZMM Pump Series')
->alignCenter()
->sortable(),
Tables\Columns\TextColumn::make('zmm_pump_model')
->label('ZMM Pump Model')
->alignCenter()
->sortable(),
Tables\Columns\TextColumn::make('zmm_ratedpower')
->label('ZMM Rated Power')
->alignCenter()
->sortable(),
Tables\Columns\TextColumn::make('zmm_region')
->label('ZMM Region')
->alignCenter()
->sortable(),
Tables\Columns\TextColumn::make('zmm_servicefactor')
->label('ZMM Service Factor')
->alignCenter()
->sortable(),
Tables\Columns\TextColumn::make('zmm_servicefactormaximumamps')
->label('ZMM Service Factor Maximum Amps')
->alignCenter()
->sortable(),
Tables\Columns\TextColumn::make('zmm_speed')
->label('ZMM Speed')
->alignCenter()
->sortable(),
Tables\Columns\TextColumn::make('zmm_suction')
->label('ZMM Suction')
->alignCenter()
->sortable(),
Tables\Columns\TextColumn::make('zmm_suctionxdelivery')
->label('ZMM Suction X Delivery')
->alignCenter()
->sortable(),
Tables\Columns\TextColumn::make('zmm_supplysource')
->label('ZMM Supply Source')
->alignCenter()
->sortable(),
Tables\Columns\TextColumn::make('zmm_temperature')
->label('ZMM Temperature')
->alignCenter()
->sortable(),
Tables\Columns\TextColumn::make('zmm_thrustload')
->label('ZMM Thrust Load')
->alignCenter()
->sortable(),
Tables\Columns\TextColumn::make('zmm_volts')
->label('ZMM Volts')
->alignCenter()
->sortable(),
Tables\Columns\TextColumn::make('zmm_wire')
->label('ZMM Wire')
->alignCenter()
->sortable(),
Tables\Columns\TextColumn::make('zmm_package')
->label('ZMM Package')
->alignCenter()
->sortable(),
Tables\Columns\TextColumn::make('zmm_pvarrayrating')
->label('ZMM PV Array Rating')
->alignCenter()
->sortable(),
Tables\Columns\TextColumn::make('zmm_isi')
->label('ZMM ISI')
->alignCenter()
->sortable(),
Tables\Columns\TextColumn::make('zmm_isimotor')
->label('ZMM ISI Motor')
->alignCenter()
->sortable(),
Tables\Columns\TextColumn::make('zmm_isipump')
->label('ZMM ISI Pump')
->alignCenter()
->sortable(),
Tables\Columns\TextColumn::make('zmm_isipumpset')
->label('ZMM ISI Pump Set')
->alignCenter()
->sortable(),
Tables\Columns\TextColumn::make('zmm_pumpset_model')
->label('ZMM Pump Set Model')
->alignCenter()
->sortable(),
Tables\Columns\TextColumn::make('zmm_stages')
->label('ZMM Stages')
->alignCenter()
->sortable(),
Tables\Columns\TextColumn::make('zmm_headrange')
->label('ZMM Head Range')
->alignCenter()
->sortable(),
Tables\Columns\TextColumn::make('zmm_overall_efficiency')
->label('ZMM Overall Efficiency')
->alignCenter()
->sortable(),
Tables\Columns\TextColumn::make('zmm_connection')
->label('ZMM Connection')
->alignCenter()
->sortable(),
Tables\Columns\TextColumn::make('zmm_min_bore_size')
->label('ZMM Min Bore Size')
->alignCenter()
->sortable(),
Tables\Columns\TextColumn::make('zmm_isireference')
->label('ZMM ISI Reference')
->alignCenter()
->sortable(),
Tables\Columns\TextColumn::make('zmm_category')
->label('ZMM Category')
->alignCenter()
->sortable(),
Tables\Columns\TextColumn::make('zmm_submergence')
->label('ZMM Submergence')
->alignCenter()
->sortable(),
Tables\Columns\TextColumn::make('zmm_capacitorstart')
->label('ZMM Capacitor Start')
->alignCenter()
->sortable(),
Tables\Columns\TextColumn::make('zmm_capacitorrun')
->label('ZMM Capacitor Run')
->alignCenter()
->sortable(),
Tables\Columns\TextColumn::make('zmm_inch')
->label('ZMM Inch')
->alignCenter()
->sortable(),
Tables\Columns\TextColumn::make('zmm_motor_type')
->label('ZMM Motor Type')
->alignCenter()
->sortable(),
Tables\Columns\TextColumn::make('zmm_dismantle_direction')
->label('ZMM Dismantle Direction')
->alignCenter()
->sortable(),
Tables\Columns\TextColumn::make('zmm_eff_ovrall')
->label('ZMM Overall Efficiency')
->alignCenter()
->sortable(),
Tables\Columns\TextColumn::make('zmm_bodymoc')
->label('ZMM Body MOC')
->alignCenter()
->sortable(),
Tables\Columns\TextColumn::make('zmm_rotormoc')
->label('ZMM Rotor MOC')
->alignCenter()
->sortable(),
Tables\Columns\TextColumn::make('zmm_dlwl')
->label('ZMM DLWL')
->alignCenter()
->sortable(),
Tables\Columns\TextColumn::make('zmm_inputpower')
->label('ZMM Input Power')
->alignCenter()
->sortable(),
Tables\Columns\TextColumn::make('zmm_imp_od')
->label('ZMM Imp OD')
->alignCenter()
->sortable(),
Tables\Columns\TextColumn::make('zmm_ambtemp')
->label('ZMM Ambient Temperature')
->alignCenter()
->sortable(),
Tables\Columns\TextColumn::make('zmm_de')
->label('ZMM DE')
->alignCenter()
->sortable(),
Tables\Columns\TextColumn::make('zmm_dischargerange')
->label('ZMM Discharge Range')
->alignCenter()
->sortable(),
Tables\Columns\TextColumn::make('zmm_efficiency_class')
->label('ZMM Efficiency Class')
->alignCenter()
->sortable(),
Tables\Columns\TextColumn::make('zmm_framesize')
->label('ZMM Frame Size')
->alignCenter()
->sortable(),
Tables\Columns\TextColumn::make('zmm_impellerdiameter')
->label('ZMM Impeller Diameter')
->alignCenter()
->sortable(),
Tables\Columns\TextColumn::make('zmm_insulationclass')
->label('ZMM Insulation Class')
->alignCenter()
->sortable(),
Tables\Columns\TextColumn::make('zmm_maxflow')
->label('ZMM Max Flow')
->alignCenter()
->sortable(),
Tables\Columns\TextColumn::make('zmm_minhead')
->label('ZMM Min Head')
->alignCenter()
->sortable(),
Tables\Columns\TextColumn::make('zmm_mtrlofconst')
->label('ZMM Motor Load Constant')
->alignCenter()
->sortable(),
Tables\Columns\TextColumn::make('zmm_nde')
->label('ZMM NDE')
->alignCenter()
->sortable(),
Tables\Columns\TextColumn::make('zmm_powerfactor')
->label('ZMM Power Factor')
->alignCenter()
->sortable(),
Tables\Columns\TextColumn::make('zmm_tagno')
->label('ZMM Tag No')
->alignCenter()
->sortable(),
Tables\Columns\TextColumn::make('zmm_year')
->label('ZMM Year')
->alignCenter()
->sortable(),
Tables\Columns\TextColumn::make('zmm_laser_name')
->label('ZMM Laser Name')
->alignCenter()
->sortable(),
Tables\Columns\TextColumn::make('zmm_beenote')
->label('ZMM Bee Note')
->alignCenter()
->sortable(),
Tables\Columns\TextColumn::make('zmm_beenumber')
->label('ZMM Bee Number')
->alignCenter()
->sortable(),
Tables\Columns\TextColumn::make('zmm_beestar')
->label('ZMM Bee Star')
->alignCenter()
->sortable(),
Tables\Columns\TextColumn::make('zmm_logo_ce')
->label('ZMM Logo CE')
->alignCenter()
->sortable(),
Tables\Columns\TextColumn::make('zmm_codeclass')
->label('ZMM Code Class')
->alignCenter()
->sortable(),
Tables\Columns\TextColumn::make('zmm_colour')
->label('ZMM Colour')
->alignCenter()
->sortable(),
Tables\Columns\TextColumn::make('zmm_logo_cp')
->label('ZMM Logo CP')
->alignCenter()
->sortable(),
Tables\Columns\TextColumn::make('zmm_grade')
->label('ZMM Grade')
->alignCenter()
->sortable(),
Tables\Columns\TextColumn::make('zmm_grwt_pset')
->label('ZMM Grwt Pset')
->alignCenter()
->sortable(),
Tables\Columns\TextColumn::make('zmm_grwt_cable')
->label('ZMM Grwt Cable')
->alignCenter()
->sortable(),
Tables\Columns\TextColumn::make('zmm_grwt_motor')
->label('ZMM Grwt Motor')
->alignCenter()
->sortable(),
Tables\Columns\TextColumn::make('zmm_grwt_pf')
->label('ZMM Grwt PF')
->alignCenter()
->sortable(),
Tables\Columns\TextColumn::make('zmm_grwt_pump')
->label('ZMM Grwt Pump')
->alignCenter()
->sortable(),
Tables\Columns\TextColumn::make('zmm_isivalve')
->label('ZMM ISIV Alve')
->alignCenter()
->sortable(),
Tables\Columns\TextColumn::make('zmm_isi_wc')
->label('ZMM ISIV WC')
->alignCenter()
->sortable(),
Tables\Columns\TextColumn::make('zmm_labelperiod')
->label('ZMM Label Period')
->alignCenter()
->sortable(),
Tables\Columns\TextColumn::make('zmm_length')
->label('ZMM Length')
->alignCenter()
->sortable(),
Tables\Columns\TextColumn::make('zmm_license_cml_no')
->label('ZMM License CML No')
->alignCenter()
->sortable(),
Tables\Columns\TextColumn::make('zmm_mfgmonyr')
->label('ZMM Mfg Mon Yr')
->alignCenter()
->sortable(),
Tables\Columns\TextColumn::make('zmm_modelyear')
->label('ZMM Model Year')
->alignCenter()
->sortable(),
Tables\Columns\TextColumn::make('zmm_motoridentification')
->label('ZMM Motor Identification')
->alignCenter()
->sortable(),
Tables\Columns\TextColumn::make('zmm_newt_pset')
->label('ZMM Newt Pset')
->alignCenter()
->sortable(),
Tables\Columns\TextColumn::make('zmm_newt_cable')
->label('ZMM Newt Cable')
->alignCenter()
->sortable(),
Tables\Columns\TextColumn::make('zmm_newt_motor')
->label('ZMM Newt Motor')
->alignCenter()
->sortable(),
Tables\Columns\TextColumn::make('zmm_newt_pf')
->label('ZMM Newt PF')
->alignCenter()
->sortable(),
Tables\Columns\TextColumn::make('zmm_newt_pump')
->label('ZMM Newt Pump')
->alignCenter()
->sortable(),
Tables\Columns\TextColumn::make('zmm_logo_nsf')
->label('ZMM Logo NSF')
->alignCenter()
->sortable(),
Tables\Columns\TextColumn::make('zmm_packtype')
->label('ZMM Pack Type')
->alignCenter()
->sortable(),
Tables\Columns\TextColumn::make('zmm_panel')
->label('ZMM Panel')
->alignCenter()
->sortable(),
Tables\Columns\TextColumn::make('zmm_performance_factor')
->label('ZMM Performance Factor')
->alignCenter()
->sortable(),
Tables\Columns\TextColumn::make('zmm_pumpidentification')
->label('ZMM Pump Identification')
->alignCenter()
->sortable(),
Tables\Columns\TextColumn::make('zmm_psettype')
->label('ZMM Pset Type')
->alignCenter()
->sortable(),
Tables\Columns\TextColumn::make('zmm_size')
->label('ZMM Size')
->alignCenter()
->sortable(),
Tables\Columns\TextColumn::make('zmm_eff_ttl')
->label('ZMM Eff TTL')
->alignCenter()
->sortable(),
Tables\Columns\TextColumn::make('zmm_type')
->label('ZMM Type')
->alignCenter()
->sortable(),
Tables\Columns\TextColumn::make('zmm_usp')
->label('ZMM USP')
->alignCenter()
->sortable(),
Tables\Columns\TextColumn::make('zmm_1')
->label('ZMM 1')
->alignCenter()
->sortable(),
Tables\Columns\TextColumn::make('zmm_2')
->label('ZMM 2')
->alignCenter()
->sortable(),
Tables\Columns\TextColumn::make('zmm_3')
->label('ZMM 3')
->alignCenter()
->sortable(),
Tables\Columns\TextColumn::make('zmm_4')
->label('ZMM 4')
->alignCenter()
->sortable(),
Tables\Columns\TextColumn::make('zmm_5')
->label('ZMM 5')
->alignCenter()
->sortable(),
Tables\Columns\TextColumn::make('zmm_6')
->label('ZMM 6')
->alignCenter()
->sortable(),
Tables\Columns\TextColumn::make('zmm_7')
->label('ZMM 7')
->alignCenter()
->sortable(),
Tables\Columns\TextColumn::make('zmm_8')
->label('ZMM 8')
->alignCenter()
->sortable(),
Tables\Columns\TextColumn::make('zmm_9')
->label('ZMM 9')
->alignCenter()
->sortable(),
Tables\Columns\TextColumn::make('zmm_10')
->label('ZMM 10')
->alignCenter()
->sortable(),
Tables\Columns\TextColumn::make('zmm_11')
->label('ZMM 11')
->alignCenter()
->sortable(),
Tables\Columns\TextColumn::make('zmm_12')
->label('ZMM 12')
->alignCenter()
->sortable(),
Tables\Columns\TextColumn::make('zmm_13')
->label('ZMM 13')
->alignCenter()
->sortable(),
Tables\Columns\TextColumn::make('zmm_14')
->label('ZMM 14')
->alignCenter()
->sortable(),
Tables\Columns\TextColumn::make('zmm_15')
->label('ZMM 15')
->alignCenter()
->sortable(),
Tables\Columns\TextColumn::make('created_by')
->label('Created By')
->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\ListItemCharacteristics::route('/'),
'create' => Pages\CreateItemCharacteristic::route('/create'),
'view' => Pages\ViewItemCharacteristic::route('/{record}'),
'edit' => Pages\EditItemCharacteristic::route('/{record}/edit'),
];
}
public static function getEloquentQuery(): Builder
{
return parent::getEloquentQuery()
->withoutGlobalScopes([
SoftDeletingScope::class,
]);
}
}

View File

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

View File

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

View File

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

View File

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

View File

@@ -82,9 +82,6 @@ class ItemResource extends Resource
Forms\Components\TextInput::make('category')
->label('Category')
->placeholder('Scan the Category'),
Forms\Components\TextInput::make('category')
->label('Category')
->placeholder('Scan the Category'),
Forms\Components\TextInput::make('code')
->required()
->placeholder('Scan the valid code')

File diff suppressed because it is too large Load Diff

View File

@@ -6,8 +6,8 @@ use AlperenErsoy\FilamentExport\Actions\FilamentExportBulkAction;
use App\Filament\Exports\ProductionPlanExporter;
use App\Filament\Imports\ProductionPlanImporter;
use App\Filament\Resources\ProductionPlanResource\Pages;
use App\Filament\Resources\ProductionPlanResource\RelationManagers;
use App\Models\Block;
use App\Models\Item;
use App\Models\Line;
use App\Models\Plant;
use App\Models\ProductionPlan;
@@ -16,18 +16,19 @@ use Carbon\Carbon;
use Filament\Facades\Filament;
use Filament\Forms;
use Filament\Forms\Components\DateTimePicker;
use Filament\Forms\Components\Section;
use Filament\Forms\Components\Select;
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\Filters\Filter;
use Filament\Tables\Table;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Database\Eloquent\SoftDeletingScope;
use Filament\Forms\Components\Section;
use Filament\Forms\Components\Select;
use Filament\Tables\Actions\ExportAction;
use Filament\Tables\Filters\Filter;
use Illuminate\Support\Facades\Request;
class ProductionPlanResource extends Resource
{
@@ -54,22 +55,22 @@ class ProductionPlanResource extends Resource
->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::orderBy('code')->pluck('name', 'id')->toArray();
return ($userHas && strlen($userHas) > 0) ? Plant::where('id', $userHas)->pluck('name', 'id')->toArray() : Plant::pluck('name', 'id')->toArray();
})
->default(function () {
return optional(ProductionPlan::latest()->first())->plant_id;
})
->disabled(fn (Get $get) => ! empty($get('id')))
->disabled(fn (Get $get) => !empty($get('id')))
// ->afterStateUpdated(fn ($set) => $set('block_name', null))
->afterStateUpdated(function ($state, callable $set, callable $get) {
$plantId = $get('plant_id');
$set('block_name', null);
if (! $plantId) {
if (!$plantId) {
$set('ppPlantError', 'Please select a plant first.');
return;
} else {
}
else
{
$set('ppPlantError', null);
}
})
@@ -78,6 +79,102 @@ class ProductionPlanResource extends Resource
])
->hint(fn ($get) => $get('ppPlantError') ? $get('ppPlantError') : null)
->hintColor('danger'),
Forms\Components\Select::make('block_name')
->required()
// ->nullable()
->label('Block')
->options(function (callable $get) {
if (!$get('plant_id')) {
return [];
}
return Block::where('plant_id', $get('plant_id'))
->pluck('name', 'id')
->toArray();
})
->reactive()
->default(function () {
$latestShiftId = optional(ProductionPlan::latest()->first())->shift_id;
return optional(Shift::where('id', $latestShiftId)->first())->block_id;
})
//->afterStateUpdated(fn ($set) => $set('shift_id', null))
->afterStateUpdated(function ($state, callable $set, callable $get) {
if($get('id'))
{
$getShift = ProductionPlan::where('id', $get('id'))->first();
$getBlock = Shift::where('id', $getShift->shift_id)->first();
if($getBlock->block_id)
{
$set('block_name', $getBlock->block_id);
$set('ppBlockError', null);
}
}
$blockId = $get('block_name');
$set('shift_id', null);
if (!$blockId) {
$set('ppBlockError', 'Please select a block first.');
return;
}
else
{
$set('ppBlockError', null);
}
})
->extraAttributes(fn ($get) => [
'class' => $get('ppBlockError') ? 'border-red-500' : '',
])
->hint(fn ($get) => $get('ppBlockError') ? $get('ppBlockError') : null)
->hintColor('danger'),
Forms\Components\Select::make('shift_id')
->relationship('shift', 'name')
->required()
// ->nullable()
->autofocus(true)
->options(function (callable $get) {
if (!$get('plant_id') || !$get('block_name')) {
return [];
}
return Shift::where('plant_id', $get('plant_id'))
->where('block_id', $get('block_name'))
->pluck('name', 'id')
->toArray();
})
->reactive()
->default(function () {
return optional(ProductionPlan::latest()->first())->shift_id;
})
// ->afterStateUpdated(fn ($set) => $set('line_id', null))
->afterStateUpdated(function ($state, callable $set, callable $get) {
if($get('id'))
{
$getShift = ProductionPlan::where('id', $get('id'))->first();
if($getShift->shift_id)
{
$set('shift_id', $getShift->shift_id);
$set('ppShiftError', null);
}
}
$curShiftId = $get('shift_id');
$set('line_id', null);
if (!$curShiftId) {
$set('ppShiftError', 'Please select a shift first.');
return;
}
else
{
$set('ppShiftError', null);
}
})
->extraAttributes(fn ($get) => [
'class' => $get('ppShiftError') ? 'border-red-500' : '',
])
->hint(fn ($get) => $get('ppShiftError') ? $get('ppShiftError') : null)
->hintColor('danger'),
Forms\Components\Select::make('line_id')
->relationship('line', 'name')
->required()
@@ -88,7 +185,7 @@ class ProductionPlanResource extends Resource
// ->toArray() // Convert collection to array
// )
->options(function (callable $get) {
if (! $get('plant_id')) {
if (!$get('plant_id') || !$get('block_name') || !$get('shift_id')) {
return [];
}
@@ -100,257 +197,248 @@ class ProductionPlanResource extends Resource
// ->default(function () {
// return optional(ProductionPlan::latest()->first())->line_id;
// })
// ->afterStateUpdated(function ($state, callable $set, callable $get) {
// if ($get('id')) {
// $getShift = ProductionPlan::where('id', $get('id'))->first();
// if ($getShift->line_id) {
// $set('line_id', $getShift->line_id);
// $set('ppLineError', null);
// }
// } else {
// $currentDT = Carbon::now()->toDateTimeString();
// $set('created_at', $currentDT);
// $set('update_date', null);
// }
// $lineId = $get('line_id');
// // $set('plan_quantity', null);
// if (! $lineId) {
// $set('ppLineError', 'Please select a line first.');
// return;
// } else {
// $isUpdate = ! empty($get('id'));
// if (! $isUpdate) {
// $exists = ProductionPlan::where('plant_id', $get('plant_id'))
// ->where('shift_id', $get('shift_id'))
// ->where('line_id', $get('line_id'))
// ->whereDate('created_at', today())
// ->latest()
// ->exists();
// if ($exists) {
// $set('line_id', null);
// $set('ppLineError', 'Production plan already updated.');
// return;
// } else {
// $existShifts = ProductionPlan::where('plant_id', $get('plant_id'))
// ->where('shift_id', $get('shift_id'))
// ->where('line_id', $get('line_id'))
// ->whereDate('created_at', Carbon::yesterday())
// ->latest()
// ->exists();
// if ($existShifts) { // if ($existShifts->count() > 0)
// // $currentDate = date('Y-m-d');
// $yesterday = date('Y-m-d', strtotime('-1 days'));
// $shiftId = Shift::where('id', $get('shift_id'))
// ->first();
// [$hRs, $miNs] = explode('.', $shiftId->duration) + [0, 0];
// $hRs = (int) $hRs;
// // $miNs = (int) $miNs;-*/
// $totalMinutes = $hRs * 60 + $miNs;
// $from_dt = $yesterday.' '.$shiftId->start_time;
// $to_dt = date('Y-m-d H:i:s', strtotime($from_dt." + $totalMinutes minutes"));
// $currentDateTime = date('Y-m-d H:i:s');
// // Check if current date time is within the range
// if ($currentDateTime >= $from_dt && $currentDateTime < $to_dt) {
// // echo "Choosed a valid shift...";
// $set('line_id', null);
// $set('ppLineError', 'Production plan already updated.');
// // $set('ppLineError', 'Valid (From: '.$from_dt.', To: '.$to_dt.')');
// return;
// } else {
// $currentDate = date('Y-m-d');
// $shiftId = Shift::where('id', $get('shift_id'))
// ->first();
// [$hRs, $miNs] = explode('.', $shiftId->duration) + [0, 0];
// $hRs = (int) $hRs;
// // $miNs = (int) $miNs;-*/
// $totalMinutes = $hRs * 60 + $miNs;
// $from_dt = $currentDate.' '.$shiftId->start_time;
// $to_dt = date('Y-m-d H:i:s', strtotime($from_dt." + $totalMinutes minutes"));
// $currentDateTime = date('Y-m-d H:i:s');
// // Check if current date time is within the range
// if (! ($currentDateTime >= $from_dt && $currentDateTime < $to_dt)) {
// // echo "Choosed a valid shift...";
// $set('line_id', null);
// $set('ppLineError', 'Choosed a invalid shift.');
// // $set('ppLineError', 'Valid (From: '.$from_dt.', To: '.$to_dt.')');
// return;
// }
// }
// $set('ppLineError', null);
// return;
// } else {
// // $currentDate = date('Y-m-d');
// $yesterday = date('Y-m-d', strtotime('-1 days'));
// $shiftId = Shift::where('id', $get('shift_id'))
// ->first();
// [$hRs, $miNs] = explode('.', $shiftId->duration) + [0, 0];
// $hRs = (int) $hRs;
// // $miNs = (int) $miNs;-*/
// $totalMinutes = $hRs * 60 + $miNs;
// $from_dt = $yesterday.' '.$shiftId->start_time;
// $to_dt = date('Y-m-d H:i:s', strtotime($from_dt." + $totalMinutes minutes"));
// $currentDateTime = date('Y-m-d H:i:s');
// // Check if current date time is within the range
// if ($currentDateTime >= $from_dt && $currentDateTime < $to_dt) {
// // echo "Choosed a valid shift...";
// // here i'm updating created as yesterday
// $set('created_at', $from_dt);
// $set('update_date', '1');
// $set('ppLineError', null);
// // $set('ppLineError', 'Valid (From: '.$from_dt.', To: '.$to_dt.')');
// return;
// } else {
// $currentDate = date('Y-m-d');
// $shiftId = Shift::where('id', $get('shift_id'))
// ->first();
// [$hRs, $miNs] = explode('.', $shiftId->duration) + [0, 0];
// $hRs = (int) $hRs;
// // $miNs = (int) $miNs;-*/
// $totalMinutes = $hRs * 60 + $miNs;
// $from_dt = $currentDate.' '.$shiftId->start_time;
// $to_dt = date('Y-m-d H:i:s', strtotime($from_dt." + $totalMinutes minutes"));
// $currentDateTime = date('Y-m-d H:i:s');
// // Check if current date time is within the range
// if (! ($currentDateTime >= $from_dt && $currentDateTime < $to_dt)) {
// // echo "Choosed a valid shift...";
// $set('line_id', null);
// $set('ppLineError', 'Choosed a invalid shift.');
// // $set('ppLineError', 'Valid (From: '.$from_dt.', To: '.$to_dt.')');
// return;
// }
// }
// $set('ppLineError', null);
// return;
// }
// // $exists = ProductionPlan::where('plant_id', $get('plant_id'))
// // //->where('shift_id', $get('shift_id'))
// // ->where('line_id', $get('line_id'))
// // ->whereDate('created_at', today())
// // ->latest() // Orders by created_at DESC
// // ->first();
// // if ($exists)
// // {
// // $existingShifts = ProductionPlan::where('plant_id', $get('plant_id'))
// // //->where('shift_id', $get('shift_id'))
// // ->where('line_id', $get('line_id'))
// // // ->whereDate('created_at', today())
// // ->whereDate('created_at', today())
// // ->get();
// // foreach ($existingShifts as $shift) {
// // $curShiftId = $shift->shift_id;
// // $currentDate = date('Y-m-d');
// // $shiftId = \App\Models\Shift::where('id', $curShiftId)
// // ->first();
// // [$hRs, $miNs] = explode('.', $shiftId->duration) + [0, 0];
// // $hRs = (int) $hRs;
// // // $miNs = (int) $miNs;-*/
// // $totalMinutes = $hRs * 60 + $miNs;
// // $from_dt = $currentDate . ' ' . $shiftId->start_time;
// // $to_dt = date('Y-m-d H:i:s', strtotime($from_dt . " + $totalMinutes minutes"));
// // $currentDateTime = date('Y-m-d H:i:s');
// // // Check if current date time is within the range
// // if ($currentDateTime >= $from_dt && $currentDateTime < $to_dt) {
// // //echo "Choosed a valid shift...";
// // // $set('ppLineError', 'Valid (From: '.$from_dt.', To: '.$to_dt.')');
// // $set('line_id', null);
// // $set('ppLineError', 'Production plan already updated.');
// // return;
// // }
// // // else {
// // // $set('ppLineError', 'Choosed a invalid shift...');
// // // return;
// // // }
// // }
// // $set('ppLineError', null);
// // return;
// // }
// }
// }
// $set('ppLineError', null);
// }
// })
->afterStateUpdated(function ($state, callable $set, callable $get) {
$set('item_id', null);
$set('plan_quantity', null);
if($get('id'))
{
$getShift = ProductionPlan::where('id', $get('id'))->first();
if($getShift->line_id)
{
$set('line_id', $getShift->line_id);
$set('ppLineError', null);
}
}
else
{
$currentDT = Carbon::now()->toDateTimeString();
$set('created_at', $currentDT);
$set('update_date', null);
}
$lineId = $get('line_id');
// $set('plan_quantity', null);
if (!$lineId) {
$set('ppLineError', 'Please select a line first.');
return;
}
else
{
$isUpdate = !empty($get('id'));
if (!$isUpdate)
{
$exists = ProductionPlan::where('plant_id', $get('plant_id'))
->where('shift_id', $get('shift_id'))
->where('line_id', $get('line_id'))
->whereDate('created_at', today())
->latest()
->exists();
if ($exists)
{
$set('line_id', null);
$set('ppLineError', 'Production plan already updated.');
return;
}
else
{
$existShifts = ProductionPlan::where('plant_id', $get('plant_id'))
->where('shift_id', $get('shift_id'))
->where('line_id', $get('line_id'))
->whereDate('created_at', Carbon::yesterday())
->latest()
->exists();
if ($existShifts) //if ($existShifts->count() > 0)
{
//$currentDate = date('Y-m-d');
$yesterday = date('Y-m-d', strtotime('-1 days'));
$shiftId = Shift::where('id', $get('shift_id'))
->first();
[$hRs, $miNs] = explode('.', $shiftId->duration) + [0, 0];
$hRs = (int) $hRs;
// $miNs = (int) $miNs;-*/
$totalMinutes = $hRs * 60 + $miNs;
$from_dt = $yesterday . ' ' . $shiftId->start_time;
$to_dt = date('Y-m-d H:i:s', strtotime($from_dt . " + $totalMinutes minutes"));
$currentDateTime = date('Y-m-d H:i:s');
// Check if current date time is within the range
if ($currentDateTime >= $from_dt && $currentDateTime < $to_dt) {
//echo "Choosed a valid shift...";
$set('line_id', null);
$set('ppLineError', 'Production plan already updated.');
// $set('ppLineError', 'Valid (From: '.$from_dt.', To: '.$to_dt.')');
return;
}
else
{
$currentDate = date('Y-m-d');
$shiftId = Shift::where('id', $get('shift_id'))
->first();
[$hRs, $miNs] = explode('.', $shiftId->duration) + [0, 0];
$hRs = (int) $hRs;
// $miNs = (int) $miNs;-*/
$totalMinutes = $hRs * 60 + $miNs;
$from_dt = $currentDate . ' ' . $shiftId->start_time;
$to_dt = date('Y-m-d H:i:s', strtotime($from_dt . " + $totalMinutes minutes"));
$currentDateTime = date('Y-m-d H:i:s');
// Check if current date time is within the range
if (!($currentDateTime >= $from_dt && $currentDateTime < $to_dt)) {
//echo "Choosed a valid shift...";
$set('line_id', null);
$set('ppLineError', 'Choosed a invalid shift.');
// $set('ppLineError', 'Valid (From: '.$from_dt.', To: '.$to_dt.')');
return;
}
}
$set('ppLineError', null);
return;
}
else
{
//$currentDate = date('Y-m-d');
$yesterday = date('Y-m-d', strtotime('-1 days'));
$shiftId = Shift::where('id', $get('shift_id'))
->first();
[$hRs, $miNs] = explode('.', $shiftId->duration) + [0, 0];
$hRs = (int) $hRs;
// $miNs = (int) $miNs;-*/
$totalMinutes = $hRs * 60 + $miNs;
$from_dt = $yesterday . ' ' . $shiftId->start_time;
$to_dt = date('Y-m-d H:i:s', strtotime($from_dt . " + $totalMinutes minutes"));
$currentDateTime = date('Y-m-d H:i:s');
// Check if current date time is within the range
if ($currentDateTime >= $from_dt && $currentDateTime < $to_dt) {
//echo "Choosed a valid shift...";
// here i'm updating created as yesterday
$set('created_at', $from_dt);
$set('update_date', '1');
$set('ppLineError', null);
// $set('ppLineError', 'Valid (From: '.$from_dt.', To: '.$to_dt.')');
return;
}
else
{
$currentDate = date('Y-m-d');
$shiftId = Shift::where('id', $get('shift_id'))
->first();
[$hRs, $miNs] = explode('.', $shiftId->duration) + [0, 0];
$hRs = (int) $hRs;
// $miNs = (int) $miNs;-*/
$totalMinutes = $hRs * 60 + $miNs;
$from_dt = $currentDate . ' ' . $shiftId->start_time;
$to_dt = date('Y-m-d H:i:s', strtotime($from_dt . " + $totalMinutes minutes"));
$currentDateTime = date('Y-m-d H:i:s');
// Check if current date time is within the range
if (!($currentDateTime >= $from_dt && $currentDateTime < $to_dt)) {
//echo "Choosed a valid shift...";
$set('line_id', null);
$set('ppLineError', 'Choosed a invalid shift.');
// $set('ppLineError', 'Valid (From: '.$from_dt.', To: '.$to_dt.')');
return;
}
}
$set('ppLineError', null);
return;
}
// $exists = ProductionPlan::where('plant_id', $get('plant_id'))
// //->where('shift_id', $get('shift_id'))
// ->where('line_id', $get('line_id'))
// ->whereDate('created_at', today())
// ->latest() // Orders by created_at DESC
// ->first();
// if ($exists)
// {
// $existingShifts = ProductionPlan::where('plant_id', $get('plant_id'))
// //->where('shift_id', $get('shift_id'))
// ->where('line_id', $get('line_id'))
// // ->whereDate('created_at', today())
// ->whereDate('created_at', today())
// ->get();
// foreach ($existingShifts as $shift) {
// $curShiftId = $shift->shift_id;
// $currentDate = date('Y-m-d');
// $shiftId = \App\Models\Shift::where('id', $curShiftId)
// ->first();
// [$hRs, $miNs] = explode('.', $shiftId->duration) + [0, 0];
// $hRs = (int) $hRs;
// // $miNs = (int) $miNs;-*/
// $totalMinutes = $hRs * 60 + $miNs;
// $from_dt = $currentDate . ' ' . $shiftId->start_time;
// $to_dt = date('Y-m-d H:i:s', strtotime($from_dt . " + $totalMinutes minutes"));
// $currentDateTime = date('Y-m-d H:i:s');
// // Check if current date time is within the range
// if ($currentDateTime >= $from_dt && $currentDateTime < $to_dt) {
// //echo "Choosed a valid shift...";
// // $set('ppLineError', 'Valid (From: '.$from_dt.', To: '.$to_dt.')');
// $set('line_id', null);
// $set('ppLineError', 'Production plan already updated.');
// return;
// }
// // else {
// // $set('ppLineError', 'Choosed a invalid shift...');
// // return;
// // }
// }
// $set('ppLineError', null);
// return;
// }
}
}
$set('ppLineError', null);
}
})
->extraAttributes(fn ($get) => [
'class' => $get('ppLineError') ? 'border-red-500' : '',
])
->hint(fn ($get) => $get('ppLineError') ? $get('ppLineError') : null)
->hintColor('danger'),
Forms\Components\Select::make('item_id')
->label('Item')
->reactive()
->searchable()
->required()
->options(function (callable $get) {
if (! $get('plant_id')) {
return [];
}
return Item::where('plant_id', $get('plant_id'))
->pluck('code', 'id')
->toArray();
}),
Forms\Components\TextInput::make('plan_quantity')
->required()
->integer()
@@ -361,18 +449,21 @@ class ProductionPlanResource extends Resource
->afterStateUpdated(function ($state, callable $set, callable $get) {
$planQuan = $get('plan_quantity');
if (! $get('update_date')) {
if (! $get('id')) {
if(!$get('update_date') )
{
if(!$get('id'))
{
$currentDT = Carbon::now()->toDateTimeString();
$set('created_at', $currentDT);
}
}
if (! $planQuan) {
if (!$planQuan) {
$set('ppPlanQuanError', 'Scan the valid plan quantity.');
return;
} else {
}
else
{
$set('ppPlanQuanError', null);
}
})
@@ -381,19 +472,29 @@ class ProductionPlanResource extends Resource
])
->hint(fn ($get) => $get('ppPlanQuanError') ? $get('ppPlanQuanError') : null)
->hintColor('danger'),
// Forms\Components\TextInput::make('production_quantity')
// ->required()
// ->integer()
// ->label('Production Quantity')
// ->readOnly(fn (callable $get) => ! $get('id'))
// ->default(0),
Forms\Components\TextInput::make('production_quantity')
->required()
->integer()
->label('Production Quantity')
->readOnly(fn (callable $get) => !$get('id'))
->default(0),
Forms\Components\TextInput::make('id')
->hidden()
->readOnly(),
Forms\Components\TextInput::make('update_date')
->hidden()
->reactive()
->readOnly(),
Forms\Components\DateTimePicker::make('created_at')
->label('Created DateTime')
->hidden()
->reactive()
->required()
->readOnly(),
Forms\Components\Hidden::make('operator_id')
->default(Filament::auth()->user()->name),
])
->columns(4),
])
->columns(2),
]);
}
@@ -428,55 +529,34 @@ class ProductionPlanResource extends Resource
$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('line.name')
->label('Plant')
->alignCenter()
->sortable()
->searchable(),
Tables\Columns\TextColumn::make('item.code')
->label('Item')
->alignCenter()
->sortable()
->searchable(),
Tables\Columns\TextColumn::make('plan_quantity')
->label('Plan Quantity')
->alignCenter()
->numeric()
->sortable()
->searchable(),
Tables\Columns\TextColumn::make('working_days')
->label('Working Days')
->alignCenter()
->numeric()
->sortable()
->searchable(),
->sortable(),
Tables\Columns\TextColumn::make('production_quantity')
->label('Production Quantity')
->alignCenter()
->numeric()
->sortable()
->searchable(),
// Tables\Columns\TextColumn::make('line.name')
// ->label('Line')
// ->alignCenter()
// ->sortable(), // ->searchable(),
// Tables\Columns\TextColumn::make('shift.block.name')
// ->label('Block')
// ->alignCenter()
// ->sortable(),
// Tables\Columns\TextColumn::make('shift.name')
// ->label('Shift')
// ->alignCenter()
// ->sortable(), // ->searchable(),
->sortable(),
Tables\Columns\TextColumn::make('line.name')
->label('Line')
->alignCenter()
->sortable(),// ->searchable(),
Tables\Columns\TextColumn::make('shift.block.name')
->label('Block')
->alignCenter()
->sortable(),
Tables\Columns\TextColumn::make('shift.name')
->label('Shift')
->alignCenter()
->sortable(),// ->searchable(),
Tables\Columns\TextColumn::make('plant.name')
->label('Plant')
->alignCenter()
->sortable(),// ->searchable(),
Tables\Columns\TextColumn::make('created_at')
->label('Created At')
->dateTime()
@@ -504,7 +584,7 @@ class ProductionPlanResource extends Resource
Filter::make('advanced_filters')
->label('Advanced Filters')
->form([
// plant
//plant
Select::make('Plant')
->label('Select Plant')
->nullable()
@@ -513,8 +593,7 @@ class ProductionPlanResource extends Resource
// })
->options(function (callable $get) {
$userHas = Filament::auth()->user()->plant_id;
return ($userHas && strlen($userHas) > 0) ? Plant::where('id', $userHas)->pluck('name', 'id')->toArray() : Plant::orderBy('code')->pluck('name', 'id')->toArray();
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) {
@@ -523,33 +602,31 @@ class ProductionPlanResource extends Resource
$set('Shift', null);
}),
// line
//line
Select::make('Line')
->label('Select line')
->nullable()
->options(function (callable $get) {
$plantId = $get('Plant');
if (! $plantId) {
if (!$plantId ) {
return [];
}
return Line::where('plant_id', $plantId)
->pluck('name', 'id');
->pluck('name', 'id');
})
->reactive(),
// block
//block
Select::make('Block')
->label('Select Block')
->nullable()
->options(function (callable $get) {
$plantId = $get('Plant');
if (! $plantId) {
if (!$plantId ) {
return [];
}
return Block::where('plant_id', $get('Plant'))->pluck('name', 'id');
})
->reactive()
@@ -557,7 +634,7 @@ class ProductionPlanResource extends Resource
$set('Shift', null);
}),
// shift
//shift
Select::make('Shift')
->label('Select Shift')
->nullable()
@@ -565,7 +642,7 @@ class ProductionPlanResource extends Resource
$plantId = $get('Plant');
$blockId = $get('Block');
if (! $plantId || ! $blockId) {
if (!$plantId || !$blockId) {
return []; // Return empty if plant or block is not selected
}
@@ -592,66 +669,52 @@ class ProductionPlanResource extends Resource
return $query->whereRaw('1 = 0');
}
if (! empty($data['Plant'])) {// if ($plant = $data['Plant'] ?? null) {
$query->where('plant_id', $data['Plant']);
} else {
$userHas = Filament::auth()->user()->plant_id;
if ($userHas && strlen($userHas) > 0) {
return $query->whereRaw('1 = 0');
}
if ($plant = $data['Plant'] ?? null) {
$query->where('plant_id', $plant);
}
if (! empty($data['Shift'])) {// if ($shift = $data['Shift'] ?? null) {
$query->where('shift_id', $data['Shift']);
if ($shift = $data['Shift'] ?? null) {
$query->where('shift_id', $shift);
}
if (! empty($data['Line'])) {// if ($line = $data['Line'] ?? null) {
$query->where('line_id', $data['Line']);
if ($line = $data['Line'] ?? null) {
$query->where('line_id', $line);
}
if (! empty($data['created_from'])) {// if ($from = $data['created_from'] ?? null) {
$query->where('created_at', '>=', $data['created_from']);
if ($from = $data['created_from'] ?? null) {
$query->where('created_at', '>=', $from);
}
if (! empty($data['created_to'])) {// if ($to = $data['created_to'] ?? null) {
$query->where('created_at', '<=', $data['created_to']);
if ($to = $data['created_to'] ?? null) {
$query->where('created_at', '<=', $to);
}
return $query;
})
->indicateUsing(function (array $data) {
$indicators = [];
if (! empty($data['Plant'])) {
$indicators[] = 'Plant: '.Plant::where('id', $data['Plant'])->value('name');
} else {
$userHas = Filament::auth()->user()->plant_id;
if ($userHas && strlen($userHas) > 0) {
return 'Plant: Choose plant to filter records.';
}
if (!empty($data['Plant'])) {
$indicators[] = 'Plant: ' . Plant::where('id', $data['Plant'])->value('name');
}
if (! empty($data['Shift'])) {
$indicators[] = 'Shift: '.Shift::where('id', $data['Shift'])->value('name');
if (!empty($data['Shift'])) {
$indicators[] = 'Shift: ' . Shift::where('id', $data['Shift'])->value('name');
}
if (! empty($data['Line'])) {
$indicators[] = 'Line: '.Line::where('id', $data['Line'])->value('name');
if (!empty($data['Line'])) {
$indicators[] = 'Line: ' . Line::where('id', $data['Line'])->value('name');
}
if (! empty($data['created_from'])) {
$indicators[] = 'From: '.$data['created_from'];
if (!empty($data['created_from'])) {
$indicators[] = 'From: ' . $data['created_from'];
}
if (! empty($data['created_to'])) {
$indicators[] = 'To: '.$data['created_to'];
if (!empty($data['created_to'])) {
$indicators[] = 'To: ' . $data['created_to'];
}
return $indicators;
}),
})
])
->filtersFormMaxHeight('280px')
->actions([
@@ -663,7 +726,7 @@ class ProductionPlanResource extends Resource
Tables\Actions\DeleteBulkAction::make(),
Tables\Actions\ForceDeleteBulkAction::make(),
Tables\Actions\RestoreBulkAction::make(),
FilamentExportBulkAction::make('export'),
FilamentExportBulkAction::make('export')
]),
])
->headerActions([
@@ -671,14 +734,14 @@ class ProductionPlanResource extends Resource
->label('Import Production Plans')
->color('warning')
->importer(ProductionPlanImporter::class)
->visible(function () {
->visible(function() {
return Filament::auth()->user()->can('view import production plan');
}),
ExportAction::make()
->label('Export Production Plans')
->color('warning')
->exporter(ProductionPlanExporter::class)
->visible(function () {
->visible(function() {
return Filament::auth()->user()->can('view export production plan');
}),
]);

View File

@@ -1,295 +0,0 @@
<?php
namespace App\Filament\Resources;
use App\Filament\Exports\RequestQuotationExporter;
use App\Filament\Imports\RequestQuotationImporter;
use App\Filament\Resources\RequestQuotationResource\Pages;
use App\Filament\Resources\RequestQuotationResource\RelationManagers;
use App\Models\RequestQuotation;
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 Illuminate\Support\Facades\Auth;
use Filament\Tables\Actions\ImportAction;
use Filament\Tables\Actions\ExportAction;
class RequestQuotationResource extends Resource
{
protected static ?string $model = RequestQuotation::class;
protected static ?string $navigationIcon = 'heroicon-o-rectangle-stack';
protected static ?string $navigationGroup = 'Request For Quotation';
public static function form(Form $form): Form
{
$canEdit = Auth::user()?->can('edit_transport_fields');
$canEditData = Auth::user()?->can('edit_all_transport_fields');
return $form
->schema([
Forms\Components\TextInput::make('rfq_number')
->label('RFQ Number')
->readOnly()
->required(),
Forms\Components\Select::make('spot_rate_transport_master_id')
->label('Group Name')
->relationship('spotRateTransportMaster', 'group_name')
->required(),
Forms\Components\DateTimePicker::make('rfq_date_time')
->label('RFQ Date Time')
->disabled(fn () => !$canEditData)
->required(),
Forms\Components\TextInput::make('pickup_address')
->label('PickUp Address')
->disabled(fn () => !$canEditData)
->required(),
Forms\Components\TextInput::make('delivery_address')
->label('Delivery Address')
->disabled(fn () => !$canEditData)
->required(),
Forms\Components\TextInput::make('weight')
->label('Weight')
->disabled(fn () => !$canEditData)
->required(),
Forms\Components\TextInput::make('volumetrice_size_inch')
->label('Volumetrice')
->disabled(fn () => !$canEditData)
->required(),
Forms\Components\TextInput::make('type_of_vehicle')
->label('Type of Vehicle')
->disabled(fn () => !$canEditData)
->required(),
Forms\Components\TextInput::make('special_type')
->label('Special Type')
->disabled(fn () => !$canEditData)
->required(),
Forms\Components\TextInput::make('no_of_vehicle')
->label('No of Vehicle')
->disabled(fn () => !$canEditData)
->required(),
Forms\Components\TextInput::make('product_name')
->label('Product Name')
->disabled(fn () => !$canEditData)
->required(),
Forms\Components\TextInput::make('loading_by')
->label('Loading By')
->disabled(fn () => !$canEditData)
->required(),
Forms\Components\TextInput::make('unloading_by')
->label('Unloading By')
->disabled(fn () => !$canEditData)
->required(),
Forms\Components\TextInput::make('pick_and_delivery')
->label('Pick and Delivery')
->disabled(fn () => !$canEditData)
->required(),
Forms\Components\TextInput::make('payment_term')
->label('Payment Term')
->disabled(fn () => !$canEditData)
->required(),
Forms\Components\TextInput::make('paid_topay')
->label('Paid Today')
->disabled(fn () => !$canEditData)
->required(),
Forms\Components\DateTimePicker::make('require_date_time')
->label('Require Date Time')
->disabled(fn () => !$canEditData)
->required(),
Forms\Components\DateTimePicker::make('rfq_rec_on_or_before')
->label('RFQ Receive On Or Before')
->disabled(fn () => !$canEditData)
->required(),
// Forms\Components\TextInput::make('transporter_name')
// ->label('Transporter Name')
// ->disabled(fn () => !($canEdit || $canEditData)),
// Forms\Components\TextInput::make('total_freight_charge')
// ->label('Total Freight Charge')
// ->disabled(fn () => !($canEdit || $canEditData)),
// Forms\Components\TextInput::make('transit_day')
// ->label('Transit Day')
// ->disabled(fn () => !($canEdit || $canEditData)),
Forms\Components\Hidden::make('created_by')
->label('Created By'),
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.')
->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('rfq_number')
->label('RFQ Number')
->alignCenter()
->sortable(),
Tables\Columns\TextColumn::make('spotRateTransportMaster.group_name')
->label('Group Name')
->alignCenter()
->sortable(),
Tables\Columns\TextColumn::make('rfq_date_time')
->label('RFQ Date Time')
->alignCenter()
->dateTime()
->sortable(),
Tables\Columns\TextColumn::make('pickup_address')
->label('PickUp Address')
->alignCenter()
->sortable(),
Tables\Columns\TextColumn::make('delivery_address')
->label('Delivery Address')
->alignCenter()
->sortable(),
Tables\Columns\TextColumn::make('weight')
->label('Weight')
->alignCenter()
->sortable(),
Tables\Columns\TextColumn::make('volumetrice_size_inch')
->label('Volumetrice Size Inch')
->alignCenter()
->sortable(),
Tables\Columns\TextColumn::make('type_of_vehicle')
->label('Type Of Vehicle')
->alignCenter()
->sortable(),
Tables\Columns\TextColumn::make('product_name')
->label('Product Name')
->alignCenter()
->sortable(),
Tables\Columns\TextColumn::make('loading_by')
->label('Loading By')
->alignCenter()
->sortable(),
Tables\Columns\TextColumn::make('unloading_by')
->label('Unloading By')
->alignCenter()
->sortable(),
Tables\Columns\TextColumn::make('unloading_by')
->label('Unloading By')
->alignCenter()
->sortable(),
Tables\Columns\TextColumn::make('pick_and_delivery')
->label('Pick and Delivery')
->alignCenter()
->sortable(),
Tables\Columns\TextColumn::make('payment_term')
->label('Payment Term')
->alignCenter()
->sortable(),
Tables\Columns\TextColumn::make('paid_topay')
->label('Paid Today')
->alignCenter()
->sortable(),
Tables\Columns\TextColumn::make('require_date_time')
->label('Require Date Time')
->alignCenter()
->sortable(),
Tables\Columns\TextColumn::make('rfq_rec_on_or_before')
->label('RFQ Receive On Or Before')
->alignCenter()
->sortable(),
Tables\Columns\TextColumn::make('transporter_name')
->label('Transporter Name')
->alignCenter()
->sortable(),
Tables\Columns\TextColumn::make('total_freight_charge')
->label('Total Freight Charge')
->alignCenter()
->sortable(),
Tables\Columns\TextColumn::make('transit_day')
->label('Transit Day')
->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 RequestQuotation')
->color('warning')
->importer(RequestQuotationImporter::class)
->visible(function() {
return Filament::auth()->user()->can('view import request quotation');
}),
ExportAction::make()
->label('Export RequestQuotation')
->color('warning')
->exporter(RequestQuotationExporter::class)
->visible(function() {
return Filament::auth()->user()->can('view export request quotation');
}),
]);
}
public static function getRelations(): array
{
return [
//
];
}
public static function getPages(): array
{
return [
'index' => Pages\ListRequestQuotations::route('/'),
'create' => Pages\CreateRequestQuotation::route('/create'),
'view' => Pages\ViewRequestQuotation::route('/{record}'),
'edit' => Pages\EditRequestQuotation::route('/{record}/edit'),
];
}
public static function getEloquentQuery(): Builder
{
return parent::getEloquentQuery()
->withoutGlobalScopes([
SoftDeletingScope::class,
]);
}
}

View File

@@ -1,40 +0,0 @@
<?php
namespace App\Filament\Resources\RequestQuotationResource\Pages;
use App\Filament\Resources\RequestQuotationResource;
use App\Models\RequestQuotation;
use Filament\Actions;
use Filament\Resources\Pages\CreateRecord;
class CreateRequestQuotation extends CreateRecord
{
protected static string $resource = RequestQuotationResource::class;
public function mount(): void
{
parent::mount();
$this->form->fill([
'rfq_number' => $this->generateRfqNumber(),
]);
}
protected function generateRfqNumber(): string
{
$year = now()->year;
$lastRfq = RequestQuotation::whereYear('created_at', $year)
->orderBy('id', 'desc')
->value('rfq_number');
if ($lastRfq) {
$lastNumber = (int) substr($lastRfq, -3);
$nextNumber = str_pad($lastNumber + 1, 3, '0', STR_PAD_LEFT);
} else {
$nextNumber = '001';
}
return "C.R.I-{$year}-{$nextNumber}";
}
}

View File

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

View File

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

View File

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

View File

@@ -1,345 +0,0 @@
<?php
namespace App\Filament\Resources;
use App\Filament\Resources\RfqTransporterBidResource\Pages;
use App\Filament\Resources\RfqTransporterBidResource\RelationManagers;
use App\Models\RfqTransporterBid;
use Filament\Facades\Filament;
use Filament\Forms;
use Filament\Forms\Components\Section;
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 Illuminate\Validation\Rule;
class RfqTransporterBidResource extends Resource
{
protected static ?string $model = RfqTransporterBid::class;
protected static ?string $navigationIcon = 'heroicon-o-rectangle-stack';
protected static ?string $navigationGroup = 'Request For Quotation';
public static function getEloquentQuery(): Builder
{
$user = Filament::auth()->user();
return parent::getEloquentQuery()
->withoutGlobalScopes([
SoftDeletingScope::class,
])
->when(
! $user->hasAnyRole(['Super Admin', 'TransporterBidSupervisor']),
fn (Builder $query) => $query
->where('transporter_name', $user->name)
->whereNotNull('request_quotation_id')
);
}
public static function form(Form $form): Form
{
return $form
->schema([
Forms\Components\Select::make('request_quotation_id')
->label('RFQ Number')
// ->relationship('requestQuotation', 'rfq_number')
->relationship(
'requestQuotation',
'rfq_number',
function (Builder $query) {
$userName = Filament::auth()->user()?->name;
$masterIds = \App\Models\SpotRateTransportMaster::whereRaw(
"user_name::jsonb @> ?",
[json_encode([$userName])]
)
->pluck('id')
->unique()
->toArray();
if (empty($masterIds)) {
$query->whereRaw('1 = 0');
return;
}
$query->whereIn('spot_rate_transport_master_id', $masterIds);
}
)
->reactive()
// ->disabled(fn ($record) => !Filament::auth()->user()?->hasAnyRole(['Super Admin', 'TransporterBidSupervisor']))
->disabled(fn ($record) =>
!Filament::auth()->user()?->hasAnyRole(['Super Admin', 'TransporterBidSupervisor'])
&& $record
)
->afterStateUpdated(function ($state, callable $set) {
$rfq = \App\Models\RequestQuotation::find($state);
if ($rfq) {
$set('pickup_address', $rfq->pickup_address);
$set('delivery_address', $rfq->delivery_address);
$set('type_of_vehicle', $rfq->type_of_vehicle);
$set('weight', $rfq->weight);
$set('volumetrice_size_inch', $rfq->volumetrice_size_inch);
$set('no_of_vehicle', $rfq->no_of_vehicle);
$set('product_name', $rfq->product_name);
$set('pick_and_delivery', $rfq->pick_and_delivery);
$set('payment_term', $rfq->payment_term);
$set('paid_topay', $rfq->paid_topay);
$set('loading_by', $rfq->loading_by);
$set('unloading_by', $rfq->unloading_by);
$set('special_type', $rfq->special_type);
$set('rfq_date_time', $rfq->rfq_date_time);
$set('require_date_time', $rfq->require_date_time);
$set('rfq_rec_on_or_before', $rfq->rfq_rec_on_or_before);
}
})
->afterStateHydrated(function ($state, callable $set) {
$rfq = \App\Models\RequestQuotation::find($state);
if ($rfq) {
$set('pickup_address', $rfq->pickup_address);
$set('delivery_address', $rfq->delivery_address);
$set('type_of_vehicle', $rfq->type_of_vehicle);
$set('weight', $rfq->weight);
$set('volumetrice_size_inch', $rfq->volumetrice_size_inch);
$set('no_of_vehicle', $rfq->no_of_vehicle);
$set('product_name', $rfq->product_name);
$set('pick_and_delivery', $rfq->pick_and_delivery);
$set('payment_term', $rfq->payment_term);
$set('paid_topay', $rfq->paid_topay);
$set('loading_by', $rfq->loading_by);
$set('unloading_by', $rfq->unloading_by);
$set('special_type', $rfq->special_type);
$set('rfq_date_time', $rfq->rfq_date_time);
$set('require_date_time', $rfq->require_date_time);
$set('rfq_rec_on_or_before', $rfq->rfq_rec_on_or_before);
}
})
->required(),
Forms\Components\Section::make('RFQ Details')
->visible(fn ($get) => $get('request_quotation_id') != null)
->reactive()
->schema([
TextInput::make('pickup_address')->label('Pickup Address')->disabled(),
TextInput::make('delivery_address')->label('Delivery Address')->disabled(),
TextInput::make('type_of_vehicle')->label('Vehicle Type')->disabled(),
TextInput::make('weight')->label('Weight')->disabled(),
TextInput::make('volumetrice_size_inch')->label('Volumetric Size')->disabled(),
TextInput::make('no_of_vehicle')->label('No. of Vehicle')->disabled(),
TextInput::make('product_name')->label('Product Name')->disabled(),
TextInput::make('pick_and_delivery')->label('Pick & Delivery')->disabled(),
TextInput::make('payment_term')->label('Payment Term')->disabled(),
TextInput::make('paid_topay')->label('Paid / To Pay')->disabled(),
TextInput::make('loading_by')->label('Loading By')->disabled(),
TextInput::make('unloading_by')->label('Unloading By')->disabled(),
TextInput::make('special_type')->label('Special Type')->disabled(),
TextInput::make('rfq_date_time')->label('RFQ Created On')->disabled(),
TextInput::make('require_date_time')->label('Required Date')->disabled(),
TextInput::make('rfq_rec_on_or_before')->label('RFQ Received On/Before')->disabled(),
]),
Forms\Components\TextInput::make('transporter_name')
->label('Transporter Name')
->readOnly()
->default(Filament::auth()->user()?->name)
->required()
->rule(function (callable $get) {
return Rule::unique('rfq_transporter_bids', 'transporter_name')
->where('request_quotation_id', $get('request_quotation_id'))
->ignore($get('id'));
}),
Forms\Components\TextInput::make('total_freight_charge')
->label('Total Freight Charge')
->required()
// ->disabled(fn ($record) => $record && $record->created_by != Filament::auth()->user()?->name)
// ->hidden(fn ($record) => !Filament::auth()->user()?->hasAnyRole(['Super Admin', 'TransporterBidSupervisor']) && $record->transporter_name != Filament::auth()->user()?->name),
->hidden(fn ($record) =>
!Filament::auth()->user()?->hasAnyRole(['Super Admin', 'TransporterBidSupervisor'])
&& ($record && $record->transporter_name != Filament::auth()->user()?->name) // Ensure $record is not null before checking transporter_name
),
Forms\Components\TextInput::make('transit_day')
->label('Transit Day')
->required()
// ->disabled(fn ($record) => $record && $record->created_by != Filament::auth()->user()?->name),
// ->hidden(fn ($record) => !Filament::auth()->user()?->hasAnyRole(['Super Admin', 'TransporterBidSupervisor']) && $record->transporter_name != Filament::auth()->user()?->name),
->hidden(fn ($record) =>
!Filament::auth()->user()?->hasAnyRole(['Super Admin', 'TransporterBidSupervisor'])
&& ($record && $record->transporter_name != Filament::auth()->user()?->name) // Ensure $record is not null before checking transporter_name
),
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('requestQuotation.rfq_number')
->label('RFQ Number')
->searchable()
->alignCenter()
->sortable(),
Tables\Columns\TextColumn::make('requestQuotation.pickup_address')
->label('PickUp Address')
->searchable()
->alignCenter()
->sortable(),
Tables\Columns\TextColumn::make('requestQuotation.delivery_address')
->label('Delivery Address')
->searchable()
->alignCenter()
->sortable(),
Tables\Columns\TextColumn::make('requestQuotation.type_of_vehicle')
->label('Type Of Vehicle')
->searchable()
->alignCenter()
->sortable(),
Tables\Columns\TextColumn::make('requestQuotation.weight')
->label('Weight')
->searchable()
->alignCenter()
->sortable(),
Tables\Columns\TextColumn::make('requestQuotation.volumetrice_size_inch')
->label('Volumetrice Size Inch')
->searchable()
->alignCenter()
->sortable(),
Tables\Columns\TextColumn::make('requestQuotation.no_of_vehicle')
->label('No Of Vehicle')
->searchable()
->alignCenter()
->sortable(),
Tables\Columns\TextColumn::make('requestQuotation.product_name')
->label('Product Name')
->searchable()
->alignCenter()
->sortable(),
Tables\Columns\TextColumn::make('requestQuotation.pick_and_delivery')
->label('Pick And Delivery')
->searchable()
->alignCenter()
->sortable(),
Tables\Columns\TextColumn::make('requestQuotation.payment_term')
->label('Payment Term')
->searchable()
->alignCenter()
->sortable(),
Tables\Columns\TextColumn::make('requestQuotation.paid_topay')
->label('Paid Today')
->searchable()
->alignCenter()
->sortable(),
Tables\Columns\TextColumn::make('requestQuotation.loading_by')
->label('Loading By')
->searchable()
->alignCenter()
->sortable(),
Tables\Columns\TextColumn::make('requestQuotation.unloading_by')
->label('Unloading By')
->searchable()
->alignCenter()
->sortable(),
Tables\Columns\TextColumn::make('requestQuotation.special_type')
->label('Special Type')
->searchable()
->alignCenter()
->sortable(),
Tables\Columns\TextColumn::make('requestQuotation.rfq_date_time')
->label('RFQ DateTime')
->searchable()
->alignCenter()
->sortable(),
Tables\Columns\TextColumn::make('requestQuotation.require_date_time')
->label('RFQ Require DateTime')
->searchable()
->alignCenter()
->sortable(),
Tables\Columns\TextColumn::make('requestQuotation.rfq_rec_on_or_before')
->label('RFQ Rec On Or Before')
->searchable()
->alignCenter()
->sortable(),
Tables\Columns\TextColumn::make('created_at')
->dateTime()
->sortable()
->toggleable(isToggledHiddenByDefault: true),
Tables\Columns\TextColumn::make('created_by')
->label('Created By')
->searchable()
->alignCenter()
->sortable(),
Tables\Columns\TextColumn::make('updated_at')
->dateTime()
->sortable()
->toggleable(isToggledHiddenByDefault: true),
Tables\Columns\TextColumn::make('updated_by')
->label('Updated By')
->searchable()
->alignCenter()
->sortable(),
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\ListRfqTransporterBids::route('/'),
'create' => Pages\CreateRfqTransporterBid::route('/create'),
'view' => Pages\ViewRfqTransporterBid::route('/{record}'),
'edit' => Pages\EditRfqTransporterBid::route('/{record}/edit'),
];
}
// public static function getEloquentQuery(): Builder
// {
// return parent::getEloquentQuery()
// ->withoutGlobalScopes([
// SoftDeletingScope::class,
// ]);
// }
}

View File

@@ -1,64 +0,0 @@
<?php
namespace App\Filament\Resources\RfqTransporterBidResource\Pages;
use App\Filament\Resources\RfqTransporterBidResource;
use App\Models\RfqTransporterBid;
use App\Models\User;
use App\Notifications\PushAlertNotification;
use Filament\Actions;
use Filament\Facades\Filament;
use Filament\Notifications\Notification;
use Filament\Resources\Pages\CreateRecord;
class CreateRfqTransporterBid extends CreateRecord
{
protected static string $resource = RfqTransporterBidResource::class;
protected function afterCreate(): void
{
$record = $this->record;
// Calculate rank based on total_freight_charge
$rank = RfqTransporterBid::where('request_quotation_id', $this->record->request_quotation_id)
->orderBy('total_freight_charge')
->pluck('id')
->search($this->record->id) + 1;
$recipients = User::role(['Super Admin', 'Rfq Supervisor'])->get();
$currentUser = Filament::auth()->user();
if ($currentUser && ! $recipients->contains('id', $currentUser->id)) {
$recipients->push($currentUser);
}
// $user1 = Filament::auth()->user();
$rfqNumber = $this->record->requestQuotation->rfq_number;
$body = "{$currentUser->name} has updated the bid for RFQ No '{$rfqNumber}'. The current rank is #{$rank}.";
Notification::make()
->title('Rank Updated')
->body("{$currentUser->name} has updated the bid for RFQ No '{$rfqNumber}'. The current rank is #{$rank}.")
->success()
->sendToDatabase($recipients);
// Push notification
foreach ($recipients as $user) {
$user->notify(
new PushAlertNotification(
'New Bid Added',
$body
)
);
}
\Log::info('Create bid notification sent', [
'bid_id' => $record->id,
'rank' => $rank,
'recipients' => $recipients->pluck('id'),
]);
}
}

View File

@@ -1,175 +0,0 @@
<?php
namespace App\Filament\Resources\RfqTransporterBidResource\Pages;
use App\Filament\Resources\RfqTransporterBidResource;
use App\Models\RequestQuotation;
use App\Models\RfqTransporterBid;
use App\Models\SpotRateTransportMaster;
use App\Models\User;
use App\Notifications\PushAlertNotification;
use Filament\Actions;
use Filament\Facades\Filament;
use Filament\Notifications\Notification;
use Filament\Resources\Pages\EditRecord;
use Illuminate\Support\Facades\Log;
class EditRfqTransporterBid extends EditRecord
{
protected static string $resource = RfqTransporterBidResource::class;
protected function afterSave(): void
{
if (! $this->record->wasChanged('total_freight_charge')) {
return;
}
$rank = RfqTransporterBid::where('request_quotation_id', $this->record->request_quotation_id)
->orderBy('total_freight_charge')
->pluck('id')
->search($this->record->id) + 1;
$requestQuotation = RequestQuotation::findOrFail(
$this->record->request_quotation_id
);
$spotRateId = $requestQuotation->spot_rate_transport_master_id;
$spotRate = SpotRateTransportMaster::findOrFail($spotRateId);
$userNames = $spotRate->user_name;
Log::info('User names from spot rate', [
'user_name_raw' => $spotRate->user_name,
]);
if (!is_array($userNames)) {
Log::warning('user_name is not array, resetting', [
'user_name' => $userNames,
]);
$userNames = [];
}
$users = User::whereIn('name', $userNames)->get();
Log::info('Matched users', [
'count' => $users->count(),
'user_ids' => $users->pluck('id'),
]);
// $recipients = User::role(['Super Admin', 'Rfq Supervisor', 'TransporterBid Employee'])->get();
// $recipients1 = User::role(['Super Admin', 'Rfq Supervisor', 'TransporterBid Employee'])->whereHas('pushSubscriptions')->get();
$currentUser = Filament::auth()->user();
// if ($currentUser && ! $recipients1->contains('id', $currentUser->id)) {
// $recipients1->push($currentUser);
// }
// if ($currentUser && ! $recipients->contains('id', $currentUser->id)) {
// $recipients->push($currentUser);
// }
// $user1 = Filament::auth()->user();
$rfqNumber = $this->record->requestQuotation->rfq_number;
$body = "{$currentUser->name} has updated the bid for RFQ No '{$rfqNumber}'. The current rank is #{$rank}.";
// Notification::make()
// ->title('Rank Updated')
// ->body("{$currentUser->name} current rank is #{$rank}")
// ->success()
// ->sendToDatabase($recipients);
// \Log::info('Notification sent', [
// 'rank' => $rank,
// 'recipients' => $recipients->pluck('id'),
// ]);
Notification::make()
->title('Rank Updated')
->body("{$currentUser->name} has updated the bid for RFQ No '{$rfqNumber}'. The current rank is #{$rank}.")
->success()
->sendToDatabase($users);
// foreach ($recipients1 as $user) {
// $user->notify(
// new PushAlertNotification(
// 'Rank Updated',
// $body
// )
// );
// }
// foreach ($users as $user) {
// Log::info('Checking push subscription for user', [
// 'user_id' => $user->id,
// 'name' => $user->name,
// 'subscription_count' => $user->pushSubscriptions()->count(),
// ]);
// if ($user->pushSubscriptions()->exists()) {
// Log::info('Sending push notification', [
// 'user_id' => $user->id,
// ]);
// $user->notify(
// new PushAlertNotification(
// 'Rank Updated',
// $body
// )
// );
// }
// else {
// Log::warning('User has NO push subscription', [
// 'user_id' => $user->id,
// ]);
// }
// }
foreach ($users as $user) {
$count = $user->pushSubscriptions()->count();
Log::info('Checking push subscription for user', [
'user_id' => $user->id,
'name' => $user->name,
'subscription_count' => $count,
]);
if ($count == 0) {
Log::warning('User has NO push subscription', [
'user_id' => $user->id,
]);
continue;
}
Log::info('Sending push notification', [
'user_id' => $user->id,
]);
// ✅ THIS IS ALL YOU NEED
$user->notify(new PushAlertNotification(
'Rank Updated',
$body
));
}
}
protected function getHeaderActions(): array
{
return [
Actions\ViewAction::make(),
Actions\DeleteAction::make(),
Actions\ForceDeleteAction::make(),
Actions\RestoreAction::make(),
];
}
}

View File

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

View File

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

View File

@@ -1,130 +0,0 @@
<?php
namespace App\Filament\Resources;
use App\Filament\Resources\SpotRateTransportMasterResource\Pages;
use App\Filament\Resources\SpotRateTransportMasterResource\RelationManagers;
use App\Models\SpotRateTransportMaster;
use App\Models\User;
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 Illuminate\Validation\Rule;
use Illuminate\Support\Facades\DB;
class SpotRateTransportMasterResource extends Resource
{
protected static ?string $model = SpotRateTransportMaster::class;
protected static ?string $navigationIcon = 'heroicon-o-rectangle-stack';
protected static ?string $navigationGroup = 'Request For Quotation';
public static function form(Form $form): Form
{
return $form
->schema([
Forms\Components\TextInput::make('group_name')
->label('Group Name')
->required(),
Forms\Components\Select::make('user_name')
->label('User')
->multiple()
->preload()
->reactive()
->options(
User::pluck('name', 'name')->toArray()
)
->searchable()
->required(),
Forms\Components\Hidden::make('id')
->label('id'),
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.')
->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('group_name')
->label('Group Name')
->sortable(),
Tables\Columns\TextColumn::make('user_name')
->label('User Name')
->sortable(),
Tables\Columns\TextColumn::make('created_at')
->label('Created At')
->dateTime()
->sortable()
->toggleable(isToggledHiddenByDefault: true),
Tables\Columns\TextColumn::make('updated_at')
->label('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\ListSpotRateTransportMasters::route('/'),
'create' => Pages\CreateSpotRateTransportMaster::route('/create'),
'view' => Pages\ViewSpotRateTransportMaster::route('/{record}'),
'edit' => Pages\EditSpotRateTransportMaster::route('/{record}/edit'),
];
}
public static function getEloquentQuery(): Builder
{
return parent::getEloquentQuery()
->withoutGlobalScopes([
SoftDeletingScope::class,
]);
}
}

View File

@@ -1,43 +0,0 @@
<?php
namespace App\Filament\Resources\SpotRateTransportMasterResource\Pages;
use App\Filament\Resources\SpotRateTransportMasterResource;
use App\Models\SpotRateTransportMaster;
use Filament\Actions;
use Filament\Notifications\Notification;
use Filament\Resources\Pages\CreateRecord;
class CreateSpotRateTransportMaster extends CreateRecord
{
protected static string $resource = SpotRateTransportMasterResource::class;
protected function beforeCreate(): void
{
$groupName = $this->data['group_name'] ?? null;
$userNames = $this->data['user_name'] ?? [];
foreach ($userNames as $userName) {
$query = SpotRateTransportMaster::where('group_name', $groupName)
->whereJsonContains('user_name', $userName);
if ($query->exists()) {
Notification::make()
->title('Duplicate User')
->body("User {$userName} already exists in this group.")
->danger()
->persistent()
->send();
// Prevent create
$this->halt();
return;
}
}
}
}

View File

@@ -1,56 +0,0 @@
<?php
namespace App\Filament\Resources\SpotRateTransportMasterResource\Pages;
use App\Filament\Resources\SpotRateTransportMasterResource;
use App\Models\SpotRateTransportMaster;
use Filament\Actions;
use Filament\Notifications\Notification;
use Filament\Resources\Pages\EditRecord;
class EditSpotRateTransportMaster extends EditRecord
{
protected static string $resource = SpotRateTransportMasterResource::class;
protected function beforeSave(): void
{
$groupName = $this->data['group_name'] ?? null;
$userNames = $this->data['user_name'] ?? [];
$recordId = $this->record->id ?? null;
foreach ($userNames as $userName) {
$query = SpotRateTransportMaster::where('group_name', $groupName)
->whereJsonContains('user_name', $userName);
// Exclude current record for update
if ($recordId) {
$query->where('id', '!=', $recordId);
}
if ($query->exists()) {
Notification::make()
->title('Duplicate User')
->body("User {$userName} already exists in this group.")
->danger()
->persistent()
->send();
// Prevent save/update
$this->halt();
return;
}
}
}
protected function getHeaderActions(): array
{
return [
Actions\ViewAction::make(),
Actions\DeleteAction::make(),
Actions\ForceDeleteAction::make(),
Actions\RestoreAction::make(),
];
}
}

View File

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

View File

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

View File

@@ -6,7 +6,6 @@ use App\Filament\Exports\StickerDetailExporter;
use App\Filament\Imports\StickerDetailImporter;
use App\Filament\Resources\StickerDetailResource\Pages;
use App\Filament\Resources\StickerDetailResource\RelationManagers;
use App\Models\ItemCharacteristic;
use App\Models\StickerDetail;
use App\Models\StickerStructureDetail;
use Filament\Tables\Actions\ExportAction;
@@ -19,8 +18,6 @@ use Filament\Tables;
use Filament\Tables\Table;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Database\Eloquent\SoftDeletingScope;
use Illuminate\Support\Facades\Schema;
use Closure;
class StickerDetailResource extends Resource
{
@@ -36,38 +33,13 @@ class StickerDetailResource extends Resource
->schema([
Forms\Components\Select::make('sticker_structure_detail_id')
->label('Sticker ID')
->reactive()
->relationship('stickerStructureDetail', 'sticker_id')
->options(function (callable $get) {
return StickerStructureDetail::pluck('sticker_id', 'id');
})
->required()
->afterStateUpdated(function (callable $get, callable $set) {
// if ($get('element_id')) {
// return;
// }
$structureId = $get('sticker_structure_detail_id');
$set('design_element_type', null);
$set('element_id', null);
if (!$structureId) {
$set('element_id', null);
return;
}
$maxId = StickerDetail::where('sticker_structure_detail_id', $structureId)
->max('element_id');
$nextId = $maxId ? ((int) $maxId + 1) : 1;
$formattedId = str_pad($nextId, 3, '0', STR_PAD_LEFT);
$set('element_id', $formattedId);
}),
->required(),
Forms\Components\Select::make('design_element_type')
->label('Design Element Type')
->reactive()
->options([
'Text' => 'Text',
'Shape' => 'Shape',
@@ -75,174 +47,66 @@ class StickerDetailResource extends Resource
'QR' => 'QR',
]),
Forms\Components\TextInput::make('element_id')
->label('Element ID')
->readOnly()
->reactive(),
->label('Element ID'),
Forms\Components\Select::make('element_type')
->label('Element Type')
->options([
'Static' => 'Static',
'Dynamic' => 'Dynamic',
]),
Forms\Components\Select::make('characteristics_type')
->label('Characteristics')
->reactive()
->options(
collect(Schema::getColumnListing('item_characteristics'))
->reject(fn ($column) => in_array($column, [
'id',
'plant_id',
'item_id',
'class',
'zz1_cn_bill_ord',
'created_at',
'updated_at',
'deleted_at',
'created_by',
'updated_by',
]))
->mapWithKeys(fn ($column) => [
$column => ucfirst(str_replace('_', ' ', $column))
])
->toArray()
),
Forms\Components\TextInput::make('string_value')
->label('String Value')
->reactive()
->visible(fn ($get) => $get('design_element_type') == 'Text'),
Forms\Components\TextInput::make('string_font')
->label('String Font')
->reactive()
->visible(fn ($get) => $get('design_element_type') == 'Text'),
Forms\Components\TextInput::make('string_size')
->label('String Size')
->reactive()
->visible(fn ($get) => $get('design_element_type') == 'Text'),
Forms\Components\Select::make('element_colour')
->label('Element Colour')
->options([
'' => 'Default (Black)',
'#000000' => 'Black',
'#FFFFFF' => 'White',
'#FF0000' => 'Red',
'#00FF00' => 'Lime',
'#0000FF' => 'Blue',
'#FFFF00' => 'Yellow',
'#00FFFF' => 'Cyan',
'#FF00FF' => 'Magenta',
'#800000' => 'Maroon',
'#808000' => 'Olive',
'#008000' => 'Green',
'#800080' => 'Purple',
'#008080' => 'Teal',
'#808080' => 'Gray',
'#C0C0C0' => 'Silver',
'#FFA500' => 'Orange',
'#FFC0CB' => 'Pink',
'#A52A2A' => 'Brown',
'#87CEEB' => 'Sky Blue',
])
->nullable()
->reactive(),
Forms\Components\Select::make('string_align')
->label('String Align')
->options([
'Left' => 'Left',
'Right' => 'Right',
'Center' => 'Center',
])
->reactive()
->visible(fn ($get) => $get('design_element_type') == 'Text'),
->label('String Size'),
Forms\Components\TextInput::make('element_colour')
->label('Element Colour'),
Forms\Components\TextInput::make('string_align')
->label('String Align'),
Forms\Components\TextInput::make('string_x_value')
->label('String X Value')
->reactive()
->visible(fn ($get) => $get('design_element_type') == 'Text'),
->label('String X Value'),
Forms\Components\TextInput::make('string_y_value')
->label('String Y Value')
->reactive()
->visible(fn ($get) => $get('design_element_type') == 'Text'),
->label('String Y Value'),
Forms\Components\Select::make('shape_name')
->label('Shape Name')
->reactive()
->options([
'Line' => 'Line',
'Rectangle' => 'Rectangle',
'CurvedRectangle' => 'CurvedRectangle',
])
->visible(fn ($get) => $get('design_element_type') == 'Shape'),
]),
Forms\Components\TextInput::make('shape_pen_size')
->label('Shape Pen Size')
->reactive()
->visible(fn ($get) => $get('design_element_type') == 'Shape'),
Forms\Components\TextInput::make('curve_radius')
->label('Curve Radius')
->reactive()
->visible(fn ($get) => $get('shape_name') == 'CurvedRectangle'),
->label('Shape Pen Size'),
Forms\Components\TextInput::make('shape_x1_value')
->label('Shape X1 Value')
->reactive()
->visible(fn ($get) => $get('design_element_type') == 'Shape'),
->label('Shape X1 Value'),
Forms\Components\TextInput::make('shape_y1_value')
->label('Shape Y1 Value')
->reactive()
->visible(fn ($get) => $get('design_element_type') == 'Shape'),
->label('Shape Y1 Value'),
Forms\Components\TextInput::make('shape_x2_value')
->label('Shape X2 Value')
->reactive()
->visible(fn ($get) => $get('design_element_type') == 'Shape'),
->label('Shape X2 Value'),
Forms\Components\TextInput::make('shape_y2_value')
->label('Shape Y2 Value')
->reactive()
->visible(fn ($get) => $get('design_element_type') == 'Shape'),
// Forms\Components\FileUpload::make('image_path')
// ->label('Image')
// ->image()
// ->directory('sticker-images')
// ->visibility('public')
// ->preserveFilenames(false)
// ->required(false)
// ->reactive()
// ->visible(fn ($get) => $get('design_element_type') == 'Image'),
// Forms\Components\TextInput::make('image_type')
// ->label('Image Type')
// ->reactive()
// ->visible(fn ($get) => $get('design_element_type') == 'Image'),
->label('Shape Y2 Value'),
Forms\Components\FileUpload::make('image_path')
->label('Image')
->image()
->directory('sticker-images')
->visibility('public')
->preserveFilenames(false)
->required(false),
Forms\Components\TextInput::make('image_type')
->label('Image Type'),
Forms\Components\TextInput::make('image_x')
->label('Image X')
->reactive()
->visible(fn ($get) => $get('design_element_type') == 'Image'),
->label('Image X'),
Forms\Components\TextInput::make('image_y')
->label('Image Y')
->reactive()
->visible(fn ($get) => $get('design_element_type') == 'Image'),
->label('Image Y'),
Forms\Components\TextInput::make('image_width')
->label('Image Width')
->reactive()
->visible(fn ($get) => $get('design_element_type') == 'Image'),
->label('Image Width'),
Forms\Components\TextInput::make('image_height')
->label('Image Height')
->reactive()
->visible(fn ($get) => $get('design_element_type') == 'Image'),
->label('Image Height'),
Forms\Components\TextInput::make('qr_value')
->label('QR Value')
->reactive()
->visible(fn ($get) => $get('design_element_type') == 'QR'),
->label('QR Value'),
Forms\Components\TextInput::make('qr_align')
->label('QR Align')
->reactive()
->visible(fn ($get) => $get('design_element_type') == 'QR'),
->label('QR Align'),
Forms\Components\TextInput::make('qr_size')
->label('QR Size')
->reactive()
->visible(fn ($get) => $get('design_element_type') == 'QR'),
->label('QR Size'),
Forms\Components\TextInput::make('qr_x_value')
->label('QR X Value')
->reactive()
->visible(fn ($get) => $get('design_element_type') == 'QR'),
->label('QR X Value'),
Forms\Components\TextInput::make('qr_y_value')
->label('QR Y Value')
->reactive()
->visible(fn ($get) => $get('design_element_type') == 'QR'),
->label('QR Y Value'),
Forms\Components\Hidden::make('created_by')
->label('created_by')
->default(Filament::auth()->user()?->name),
@@ -278,9 +142,6 @@ class StickerDetailResource extends Resource
Tables\Columns\TextColumn::make('element_type')
->label('Element Type')
->alignCenter(),
Tables\Columns\TextColumn::make('characteristics_type')
->label('Characteristics Type')
->alignCenter(),
Tables\Columns\TextColumn::make('string_value')
->label('String Value')
->alignCenter(),
@@ -290,9 +151,9 @@ class StickerDetailResource extends Resource
Tables\Columns\TextColumn::make('string_size')
->label('String Size')
->alignCenter(),
// Tables\Columns\TextColumn::make('element_colour')
// ->label('Element Colour')
// ->alignCenter(),
Tables\Columns\TextColumn::make('element_colour')
->label('Element Colour')
->alignCenter(),
Tables\Columns\TextColumn::make('string_align')
->label('String Align')
->alignCenter(),
@@ -308,8 +169,6 @@ class StickerDetailResource extends Resource
Tables\Columns\TextColumn::make('shape_pen_size')
->label('Shape Pen Size')
->alignCenter(),
Tables\Columns\TextColumn::make('curve_radius')
->label('Curve Radius'),
Tables\Columns\TextColumn::make('shape_x1_value')
->label('Shape X1 Value')
->alignCenter(),
@@ -322,6 +181,12 @@ class StickerDetailResource extends Resource
Tables\Columns\TextColumn::make('shape_y2_value')
->label('Shape Y2 Value')
->alignCenter(),
Tables\Columns\TextColumn::make('image_path')
->label('Image Path')
->alignCenter(),
Tables\Columns\TextColumn::make('image_type')
->label('Image Type')
->alignCenter(),
Tables\Columns\TextColumn::make('image_x')
->label('Image X')
->alignCenter(),

View File

@@ -6,24 +6,18 @@ use App\Filament\Exports\StickerMappingMasterExporter;
use App\Filament\Imports\StickerMappingMasterImporter;
use App\Filament\Resources\StickerMappingMasterResource\Pages;
use App\Filament\Resources\StickerMappingMasterResource\RelationManagers;
use App\Models\Item;
use App\Models\ItemCharacteristic;
use App\Models\Machine;
use App\Models\Plant;
use App\Models\StickerMappingMaster;
use App\Models\StickerStructureDetail;
use Filament\Facades\Filament;
use Filament\Forms;
use Filament\Forms\Components\Section;
use Filament\Forms\Components\Select;
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\Tables\Actions\ExportAction;
use Filament\Tables\Actions\ImportAction;
use Filament\Tables\Actions\ExportAction;
class StickerMappingMasterResource extends Resource
{
@@ -31,424 +25,143 @@ class StickerMappingMasterResource extends Resource
protected static ?string $navigationIcon = 'heroicon-o-rectangle-stack';
protected static ?string $navigationGroup = 'Customized Sticker Printing';
// public static function form(Form $form): Form
// {
// return $form
// ->schema([
// Forms\Components\TextInput::make('plant_id')
// ->required()
// ->numeric(),
// Forms\Components\TextInput::make('item_id')
// ->required()
// ->numeric(),
// Forms\Components\Textarea::make('sticker1')
// ->columnSpanFull(),
// Forms\Components\Textarea::make('sticker2')
// ->columnSpanFull(),
// Forms\Components\Textarea::make('sticker3')
// ->columnSpanFull(),
// Forms\Components\Textarea::make('sticker4')
// ->columnSpanFull(),
// Forms\Components\Textarea::make('sticker5')
// ->columnSpanFull(),
// Forms\Components\Textarea::make('created_by')
// ->columnSpanFull(),
// Forms\Components\Textarea::make('updated_by')
// ->columnSpanFull(),
// ]);
// }
protected static ?string $navigationGroup = 'Master Entries';
protected static ?int $navigationSort = 16;
public static function form(Form $form): Form
{
return $form
->schema([
/* -------- Basic Mapping -------- */
Section::make('Basic Mapping')
->schema([
Select::make('plant_id')
->label('Plant')
->reactive()
->relationship('plant', 'name')
->required(),
Select::make('item_characteristic_id')
->label('Item Code')
->reactive()
//->relationship('item', 'code')
->options(function (callable $get) {
{
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')
->reactive()
->options(function (callable $get) {
$plantId = $get('plant_id');
if (! $plantId) {
if (empty($plantId)) {
return [];
}
return ItemCharacteristic::query()
->whereHas('item', function ($query) use ($plantId) {
$query->where('plant_id', $plantId);
})
->with('item')
->get()
->mapWithKeys(fn ($ic) => [
$ic->id => $ic->item->code,
]);
return \App\Models\Item::where('plant_id', $plantId)->pluck('code', 'id');
})
->searchable()
->required(),
])
->columns(2),
Forms\Components\TextInput::make('sticker1')
->label('Sticker Label 1')
->required(),
Forms\Components\TextInput::make('sticker2')
->label('Sticker Label 2'),
Forms\Components\TextInput::make('sticker3')
->label('Sticker Label 3'),
Forms\Components\TextInput::make('sticker4')
->label('Sticker Label 4'),
Forms\Components\TextInput::make('sticker5')
->label('Sticker Label 5'),
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),
]);
}
/* -------- Sticker 1 -------- */
Section::make('Sticker 1')
->schema([
Select::make('sticker_structure1_id')
->label('Sticker ID')
->options(function (callable $get) {
return StickerStructureDetail::pluck('sticker_id', 'id');
})
->searchable(),
Select::make('sticker1_machine_id')
->label('Work Center')
//->relationship('sticker1Machine', 'name')
->options(function (callable $get) {
$plantId = $get('plant_id');
if (empty($plantId)) {
return [];
}
return Machine::where('plant_id', $plantId)->pluck('work_center', 'id');
})
->searchable(),
TextInput::make('sticker1_print_ip')
->label('Printer IP')
->ipv4(),
])
->columns(2),
/* -------- Sticker 2 -------- */
Section::make('Sticker 2')
->schema([
Select::make('sticker_structure2_id')
->label('Sticker ID')
->options(function (callable $get) {
return StickerStructureDetail::pluck('sticker_id', 'id');
})
->searchable(),
Select::make('sticker2_machine_id')
->label('Work Center')
// ->relationship('sticker2Machine', 'name')
->options(function (callable $get) {
$plantId = $get('plant_id');
if (empty($plantId)) {
return [];
}
return Machine::where('plant_id', $plantId)->pluck('work_center', 'id');
})
->searchable(),
TextInput::make('sticker2_print_ip')
->label('Printer IP')
->ipv4(),
])
->columns(2),
/* -------- Sticker 3 -------- */
Section::make('Sticker 3')
->schema([
Select::make('sticker_structure3_id')
->label('Sticker ID')
->options(function (callable $get) {
return StickerStructureDetail::pluck('sticker_id', 'id');
})
->searchable(),
Select::make('sticker3_machine_id')
->label('Work Center')
//->relationship('sticker3Machine', 'name')
->options(function (callable $get) {
$plantId = $get('plant_id');
if (empty($plantId)) {
return [];
}
return Machine::where('plant_id', $plantId)->pluck('work_center', 'id');
})
->searchable(),
TextInput::make('sticker3_print_ip')
->label('Printer IP')
->ipv4(),
])
->columns(2),
/* -------- Sticker 4 -------- */
Section::make('Sticker 4')
->schema([
Select::make('sticker_structure4_id')
->label('Sticker ID')
->options(function (callable $get) {
return StickerStructureDetail::pluck('sticker_id', 'id');
})
->searchable(),
Select::make('sticker4_machine_id')
->label('Work Center')
//->relationship('sticker4Machine', 'name')
->options(function (callable $get) {
$plantId = $get('plant_id');
if (empty($plantId)) {
return [];
}
return Machine::where('plant_id', $plantId)->pluck('work_center', 'id');
})
->searchable(),
TextInput::make('sticker4_print_ip')
->label('Printer IP')
->ipv4(),
])
->columns(2),
/* -------- Sticker 5 -------- */
Section::make('Sticker 5')
->schema([
Select::make('sticker_structure5_id')
->label('Sticker ID')
->options(function (callable $get) {
return StickerStructureDetail::pluck('sticker_id', 'id');
})
->searchable(),
Select::make('sticker5_machine_id')
->label('Work Center')
//->relationship('sticker5Machine', 'name')
->options(function (callable $get) {
$plantId = $get('plant_id');
if (empty($plantId)) {
return [];
}
return Machine::where('plant_id', $plantId)->pluck('work_center', 'id');
})
->searchable(),
TextInput::make('sticker5_print_ip')
->label('Printer IP')
->ipv4(),
])
->columns(2),
/* -------- Sticker 6 -------- */
Section::make('Sticker 6')
->schema([
Select::make('sticker_structure6_id')
->label('Sticker ID')
->options(function (callable $get) {
return StickerStructureDetail::pluck('sticker_id', 'id');
})
->searchable(),
Select::make('sticker6_machine_id')
->label('Work Center')
//->relationship('sticker6Machine', 'name')
->options(function (callable $get) {
$plantId = $get('plant_id');
if (empty($plantId)) {
return [];
}
return Machine::where('plant_id', $plantId)->pluck('work_center', 'id');
})
->searchable(),
TextInput::make('sticker6_print_ip')
->label('Printer IP')
->ipv4(),
])
->columns(2),
/* -------- Sticker 7 -------- */
Section::make('Sticker 7')
->schema([
Select::make('sticker_structure7_id')
->label('Sticker ID')
->options(function (callable $get) {
return StickerStructureDetail::pluck('sticker_id', 'id');
})
->searchable(),
Select::make('sticker7_machine_id')
->label('Work Center')
//->relationship('sticker7Machine', 'name')
->options(function (callable $get) {
$plantId = $get('plant_id');
if (empty($plantId)) {
return [];
}
return Machine::where('plant_id', $plantId)->pluck('work_center', 'id');
})
->searchable(),
TextInput::make('sticker7_print_ip')
->label('Printer IP')
->ipv4(),
])
->columns(2),
/* -------- Sticker 8 -------- */
Section::make('Sticker 8')
->schema([
Select::make('sticker_structure8_id')
->label('Sticker ID')
->options(function (callable $get) {
return StickerStructureDetail::pluck('sticker_id', 'id');
})
->searchable(),
Select::make('sticker8_machine_id')
->label('Work Center')
//->relationship('sticker8Machine', 'name')
->options(function (callable $get) {
$plantId = $get('plant_id');
if (empty($plantId)) {
return [];
}
return Machine::where('plant_id', $plantId)->pluck('work_center', 'id');
})
->searchable(),
TextInput::make('sticker8_print_ip')
->label('Printer IP')
->ipv4(),
])
->columns(2),
]);
}
public static function table(Table $table): Table
{
return $table
->columns([
Tables\Columns\TextColumn::make('No.')
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('itemCharacteristic.item.code')
->label('Item')
->alignCenter()
->sortable(),
Tables\Columns\TextColumn::make('sticker1Structure.sticker_id')
->label('Sticker 1')
->alignCenter(),
Tables\Columns\TextColumn::make('sticker1Machine.work_center')
->label('WC 1')
->alignCenter(),
Tables\Columns\TextColumn::make('sticker1_print_ip')
->label('Printer IP 1')
->alignCenter(),
Tables\Columns\TextColumn::make('sticker2Structure.sticker_id')
->label('Sticker 2')
->alignCenter(),
Tables\Columns\TextColumn::make('sticker2Machine.work_center')
->label('WC 2')
->alignCenter(),
Tables\Columns\TextColumn::make('sticker2_print_ip')
->label('Printer IP 2')
->alignCenter(),
Tables\Columns\TextColumn::make('sticker3Structure.sticker_id')
->label('Sticker 3')
->alignCenter(),
Tables\Columns\TextColumn::make('sticker3Machine.work_center')
->label('WC 3')
->alignCenter(),
Tables\Columns\TextColumn::make('sticker3_print_ip')
->label('Printer IP 3')
->alignCenter(),
Tables\Columns\TextColumn::make('sticker4Structure.sticker_id')
->label('Sticker 4')
->alignCenter(),
Tables\Columns\TextColumn::make('sticker4Machine.work_center')
->label('WC 4')
->alignCenter(),
Tables\Columns\TextColumn::make('sticker4_print_ip')
->label('Printer IP 4')
->alignCenter(),
Tables\Columns\TextColumn::make('sticker5Structure.sticker_id')
->label('Sticker 5')
->alignCenter(),
Tables\Columns\TextColumn::make('sticker5Machine.work_center')
->label('WC 5')
->alignCenter(),
Tables\Columns\TextColumn::make('sticker5_print_ip')
->label('Printer IP 5')
->alignCenter(),
Tables\Columns\TextColumn::make('sticker6Structure.sticker_id')
->label('Sticker 6')
->alignCenter(),
Tables\Columns\TextColumn::make('sticker6Machine.work_center')
->label('WC 6')
->alignCenter(),
Tables\Columns\TextColumn::make('sticker6_print_ip')
->label('Printer IP 6')
->alignCenter(),
Tables\Columns\TextColumn::make('sticker7Structure.sticker_id')
->label('Sticker 7')
->alignCenter(),
Tables\Columns\TextColumn::make('sticker7Machine.work_center')
->label('WC 7')
->alignCenter(),
Tables\Columns\TextColumn::make('sticker7_print_ip')
->label('Printer IP 7')
->alignCenter(),
Tables\Columns\TextColumn::make('sticker8Structure.sticker_id')
->label('Sticker 8')
->alignCenter(),
Tables\Columns\TextColumn::make('sticker8Machine.work_center')
->label('WC 8')
->alignCenter(),
Tables\Columns\TextColumn::make('sticker8_print_ip')
->label('Printer IP 8')
->alignCenter(),
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()
->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()
->importer(StickerMappingMasterImporter::class)
->label('Import Sticker Mapping Master')
->color('warning')
->visible(function () {
return Filament::auth()->user()->can('view import sticker mapping master');
}),
ExportAction::make()
->exporter(StickerMappingMasterExporter::class)
->label('Export Sticker Mapping Master')
->color('warning')
->visible(function () {
return Filament::auth()->user()->can('view export sticker mapping master');
}),
]);
Tables\Columns\TextColumn::make('plant.name')
->label('Plant')
->alignCenter()
->sortable(),
Tables\Columns\TextColumn::make('item.code')
->label('Item Code')
->alignCenter()
->sortable(),
Tables\Columns\TextColumn::make('sticker1')
->label('Sticker Label 1')
->alignCenter()
->sortable(),
Tables\Columns\TextColumn::make('sticker2')
->label('Sticker Label 2')
->alignCenter()
->sortable(),
Tables\Columns\TextColumn::make('sticker3')
->label('Sticker Label 3')
->alignCenter()
->sortable(),
Tables\Columns\TextColumn::make('sticker4')
->label('Sticker Label 4')
->alignCenter()
->sortable(),
Tables\Columns\TextColumn::make('sticker5')
->label('Sticker Label 5')
->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 Sticker Mapping Masters')
->color('warning')
->importer(StickerMappingMasterImporter::class)
->visible(function() {
return Filament::auth()->user()->can('view import sticker mapping master');
}),
ExportAction::make()
->label('Export Sticker Mapping Masters')
->color('warning')
->exporter(StickerMappingMasterExporter::class)
->visible(function() {
return Filament::auth()->user()->can('view export sticker mapping master');
}),
]);
}
public static function getRelations(): array

View File

@@ -6,7 +6,6 @@ use App\Filament\Exports\StickerStructureDetailExporter;
use App\Filament\Imports\StickerStructureDetailImporter;
use App\Filament\Resources\StickerStructureDetailResource\Pages;
use App\Filament\Resources\StickerStructureDetailResource\RelationManagers;
use App\Models\ItemCharacteristic;
use App\Models\StickerStructureDetail;
use Filament\Facades\Filament;
use Filament\Forms;
@@ -35,31 +34,6 @@ class StickerStructureDetailResource extends Resource
{
return $form
->schema([
Forms\Components\Select::make('plant_id')
->label('Plant')
->relationship('plant', 'name')
->reactive(),
Forms\Components\Select::make('item_characteristic_id')
->label('Item')
->reactive()
->options(function (callable $get) {
$plantId = $get('plant_id');
if (! $plantId) {
return [];
}
return ItemCharacteristic::query()
->whereHas('item', function ($query) use ($plantId) {
$query->where('plant_id', $plantId);
})
->with('item')
->get()
->mapWithKeys(fn ($ic) => [
$ic->id => $ic->item->code,
]);
})
->searchable(),
Forms\Components\TextInput::make('sticker_id')
->label('Sticker ID')
->reactive()
@@ -92,31 +66,41 @@ class StickerStructureDetailResource extends Resource
Forms\Components\Hidden::make('updated_by')
->label('Updated By')
->default(Filament::auth()->user()?->name),
Forms\Components\Hidden::make('sticker_id_live')
Forms\Components\TextInput::make('sticker_id_live')
->default(fn ($get) => $get('sticker_id'))
->reactive()
->afterStateUpdated(function ($state, callable $set) {
\Log::info('Sticker ID Live:', ['sticker_id_live' => $state]);
$set('sticker_id_live', $state);
}),
Forms\Components\ViewField::make('generate_template')
->view('fields.generate-template')
->reactive()
//->key(fn ($get) => 'generate-template' . ($get('sticker_id_live') ?? 'empty'))
->key(fn (Get $get) =>
'generate-template-' .
($get('sticker_id_live') ?? 'empty') . '-' .
($get('plant_id') ?? 'empty') . '-' .
($get('item_characteristic_id') ?? 'empty')
)
// ->viewData(fn (Get $get) => [
// 'sticker_id' => $get('sticker_id_live') ?? 'empty',
// ]),
->key(fn ($get) => 'generate-template' . ($get('sticker_id_live') ?? 'empty'))
->viewData(fn (Get $get) => [
'sticker_id' => $get('sticker_id_live') ?? 'empty',
'plant_id' => $get('plant_id') ?? 'empty',
'item_characteristic_id' => $get('item_characteristic_id') ?? 'empty',
])
// ->extraAttributes([
// // Pass the current sticker_id typed by the user
// //'sticker_id' => fn ($get) => $get('sticker_id'),
// 'sticker_id' => fn ($get) => $get('sticker_id') ?? 'empty',
// // 'sticker_id' => function ($get) {
// // \Log::info('ViewField closure executed');
// // $stickerId = $get('sticker_id');
// // // Use Laravel log to see value in real time
// // \Log::info('Sticker ID in ViewField:', $stickerId);
// // // You can also temporarily dd(), but it will stop form render
// // // dd($stickerId);
// // return $stickerId;
// // },
// ]),
]);
}

View File

@@ -1,165 +0,0 @@
<?php
namespace App\Filament\Resources;
use App\Filament\Resources\StickerValidationResource\Pages;
use App\Filament\Resources\StickerValidationResource\RelationManagers;
use App\Models\Machine;
use App\Models\StickerValidation;
use Filament\Facades\Filament;
use Filament\Forms;
use Filament\Forms\Components\Section;
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;
class StickerValidationResource extends Resource
{
protected static ?string $model = StickerValidation::class;
protected static ?string $navigationIcon = 'heroicon-o-rectangle-stack';
protected static ?string $navigationGroup = 'Customized Sticker Printing';
public static function form(Form $form): Form
{
return $form
->schema([
Section::make('')
->schema([
Forms\Components\Select::make('plant_id')
->label('Plant')
->reactive()
->relationship('plant', 'name')
->required(),
Forms\Components\Select::make('machine_id')
->label('Work Center')
->required()
->reactive()
->options(function (callable $get) {
$plantId = $get('plant_id');
if (empty($plantId)) {
return [];
}
return Machine::where('plant_id', $plantId)->pluck('work_center', 'id');
})
->searchable(),
Forms\Components\TextInput::make('production_order')
->label('Production Order')
->reactive()
->extraAttributes([
'id' => 'production_order_input',
'x-data' => '{ value: "" }',
'x-model' => 'value',
'wire:keydown.enter.prevent' => 'processProOrder(value)',
]),
Forms\Components\TextInput::make('serial_number')
->label('Serial Number')
->reactive()
->extraAttributes([
'id' => 'serial_number_input',
'x-data' => '{ value: "" }',
'x-model' => 'value',
'wire:keydown.enter.prevent' => 'processSno(value)',
]),
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.')
->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()
->sortable(),
Tables\Columns\TextColumn::make('machine.work_center')
->label('Work Center')
->alignCenter()
->sortable(),
Tables\Columns\TextColumn::make('production_order')
->label('Production Order')
->alignCenter()
->sortable(),
Tables\Columns\TextColumn::make('serial_number')
->label('Serial Number')
->alignCenter()
->sortable(),
Tables\Columns\TextColumn::make('status')
->label('Status')
->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\ListStickerValidations::route('/'),
'create' => Pages\CreateStickerValidation::route('/create'),
'view' => Pages\ViewStickerValidation::route('/{record}'),
'edit' => Pages\EditStickerValidation::route('/{record}/edit'),
];
}
public static function getEloquentQuery(): Builder
{
return parent::getEloquentQuery()
->withoutGlobalScopes([
SoftDeletingScope::class,
]);
}
}

View File

@@ -1,416 +0,0 @@
<?php
namespace App\Filament\Resources\StickerValidationResource\Pages;
use App\Filament\Resources\StickerValidationResource;
use App\Models\Item;
use App\Models\ItemCharacteristic;
use App\Models\ProductionQuantity;
use App\Models\StickerDetail;
use App\Models\StickerMappingMaster;
use App\Models\StickerStructureDetail;
use App\Models\StickerValidation;
use App\Services\StickerPdfService;
use Filament\Actions;
use Filament\Facades\Filament;
use Filament\Notifications\Notification;
use Filament\Resources\Pages\CreateRecord;
class CreateStickerValidation extends CreateRecord
{
protected static string $resource = StickerValidationResource::class;
protected static string $view = 'filament.resources.sticker-validation-resource.create-sticker-validation';
public $ref_number;
public $plantId;
public $workCenter;
public $serNo;
public function getFormActions(): array
{
return [
$this->getCancelFormAction(),
];
}
protected function getRedirectUrl(): string
{
return $this->getResource()::getUrl('create');
}
public function processProOrder($value)
{
$plantId = $this->form->getState()['plant_id'];
$this->plantId = $plantId;
$this->ref_number = $value;
$this->dispatch('refreshEmptySticker', $plantId, $value);
$this->dispatch('focus-serial-number');
}
public function processSno($serNo)
{
$plantId = $this->form->getState()['plant_id'];
$this->plantId = $plantId;
$workCenter = $this->form->getState()['machine_id'];
$this->workCenter = $workCenter;
$this->ref_number = $this->form->getState()['production_order'];
$this->serNo = $serNo;
$user = Filament::auth()->user();
$operatorName = $user->name;
if (! preg_match('/^([a-zA-Z0-9]{6,})\|([1-9][a-zA-Z0-9]{8,})\|?$/', $this->serNo, $matches)) {
Notification::make()
->danger()
->title('Invalid Serial QR Format')
->body('Scan valid Serial QR code proceed!<br>Sample formats are:<br>123456|1234567890123| OR 123456|1234567890123')
->seconds(3)
->send();
$this->dispatch('playWarnSound');
$this->form->fill([
'plant_id' => $this->plantId,
'machine_id' => $this->workCenter,
'production_order' => $this->ref_number,
'serial_number' => null,
]);
$this->dispatch('focus-serial-number');
return;
}
else {
$itemCode = $matches[1];
$serialNumber = $matches[2];
$recFound = ProductionQuantity::where('plant_id', $this->plantId)
->where('production_order', $this->ref_number)
->where('serial_number', $serialNumber)
->first();
if(!$recFound){
Notification::make()
->danger()
->title('Unknown Serial Number')
->body("Scanned serial number '$serialNumber' not found for the given plant and production order")
->seconds(3)
->send();
$this->form->fill([
'plant_id' => $this->plantId,
'machine_id' => $this->workCenter,
'production_order' => $this->ref_number,
'serial_number' => null,
]);
return;
}
$duplicate = StickerValidation::where('plant_id', $this->plantId)
->where('production_order', $this->ref_number)
->where('serial_number', $serialNumber)
->first();
if ($duplicate) {
Notification::make()
->danger()
->title('Duplicate Serial Number')
->body("Serial number $serialNumber already exists for this plant and production order!")
->seconds(3)
->send();
$this->form->fill([
'plant_id' => $this->plantId,
'machine_id' => $this->workCenter,
'production_order' => $this->ref_number,
'serial_number' => null,
]);
return;
}
$itemC = Item::where('code', $itemCode)
->where('plant_id',$this->plantId)
->first();
$itemId = $itemC->id;
$item = ItemCharacteristic::where('item_id', $itemId)
->where('plant_id',$this->plantId)
->first();
$itemI = $item->id;
$mapping = StickerMappingMaster::where('plant_id', $this->plantId)
->where('item_characteristic_id', $itemI)
->first();
if (!$mapping) {
Notification::make()
->danger()
->title('Sticker Mapping Not Found')
->body("No sticker mapping found for this item and plant.")
->send();
return;
}
$stickers = [];
for ($i = 1; $i <= 8; $i++) {
$machineColumn = "sticker{$i}_machine_id";
$ipColumn = "sticker{$i}_print_ip";
$stickerColumn = "sticker_structure{$i}_id";
$itemColumn = "item_characteristic_id";
if (
!empty($mapping->$machineColumn) &&
!empty($mapping->$stickerColumn)
) {
$stickers[] = [
'machine_id' => $mapping->$machineColumn,
'sticker_id' => $mapping->$stickerColumn,
'item_characteristic' => $mapping->$itemColumn,
'print_ip' => $mapping->$ipColumn,
];
}
}
if (empty($stickers)) {
Notification::make()
->danger()
->title('No Sticker Configuration Found')
->body('No sticker and machine mappings configured for this item and plant.')
->send();
return;
}
StickerValidation::create([
'plant_id' => $this->plantId,
'machine_id' => $this->workCenter,
'production_order' => $this->ref_number ?? null,
'serial_number' => $serialNumber,
'status' => 'Printed',
// 'sticker_id' => $matchedSticker,
'created_by' => $operatorName,
'created_at' => now(),
'updated_at' => now(),
]);
Notification::make()
->success()
->title('Sticker Recorded')
->body("Item: $itemCode, Serial: $serialNumber recorded successfully!")
->seconds(3)
->send();
$this->form->fill([
'plant_id' => $this->plantId,
'machine_id' => $this->workCenter,
'production_order' => $this->ref_number,
'serial_number' => null,
]);
$this->dispatch('refreshEmptySticker', $plantId, $this->ref_number);
// foreach ($stickers as $sticker) {
// // $printerName = $this->getCupsPrinterNameByIp($sticker['print_ip']);
// \Log::info("Looking up printer for IP: " . $sticker['print_ip']);
// $printerName = $this->getCupsPrinterNameByIp($sticker['print_ip']);
// \Log::info("Found printer: " . ($printerName ?? 'NULL'));
// if (! $printerName) {
// Notification::make()
// ->danger()
// ->title('Printer Not Found')
// ->body("No CUPS printer configured for IP: {$sticker['print_ip']}")
// ->send();
// return;
// }
// $structure = StickerStructureDetail::findOrFail($sticker['sticker_id']);
// $itemCharacteristic = ItemCharacteristic::where('plant_id', $this->plantId)
// ->where('id', $sticker['item_characteristic'])
// ->firstOrFail();
// $dynamicElements = StickerDetail::where(
// 'sticker_structure_detail_id',
// $structure->id
// )->where('element_type', 'Dynamic')->get();
// /** STEP 3: Stream PDF to CUPS (STDIN) */
// $process = proc_open(
// 'lp -d ' . escapeshellarg($printerName) . ' -o fit-to-page -',
// [
// ['pipe', 'r'], // STDIN
// ['pipe', 'w'], // STDOUT
// ['pipe', 'w'], // STDERR
// ],
// $pipes
// );
// if (! is_resource($process)) {
// Notification::make()
// ->danger()
// ->title('Print Failed')
// ->body('Unable to start CUPS print process.')
// ->send();
// return;
// // continue;
// }
// $pdfContent = (new StickerPdfService())->generatePdf1(
// $structure->sticker_id,
// $dynamicElements,
// $itemCharacteristic,
// $serialNumber,
// $serNo
// );
// fwrite($pipes[0], $pdfContent);
// fclose($pipes[0]);
// $stderr = stream_get_contents($pipes[2]);
// fclose($pipes[1]);
// fclose($pipes[2]);
// $status = proc_close($process);
// if ($status != 0) {
// Notification::make()
// ->danger()
// ->title('Print Failed')
// ->body("CUPS error: {$stderr}")
// ->send();
// return;
// }
// }
foreach ($stickers as $sticker)
{
\Log::info("Looking up printer for IP: " . $sticker['print_ip']);
$printerName = $this->getCupsPrinterNameByIp($sticker['print_ip']);
\Log::info("Found printer: " . ($printerName ?? 'NULL'));
if (! $printerName) {
Notification::make()
->danger()
->title('Printer Not Found')
->body("No CUPS printer configured for IP: {$sticker['print_ip']}")
->send();
return;
}
$structure = StickerStructureDetail::findOrFail($sticker['sticker_id']);
$itemCharacteristic = ItemCharacteristic::where('plant_id', $this->plantId)
->where('id', $sticker['item_characteristic'])
->firstOrFail();
$dynamicElements = StickerDetail::where(
'sticker_structure_detail_id',
$structure->id
)->where('element_type', 'Dynamic')->get();
$pdfContent = (new StickerPdfService())->generatePdf1(
$structure->sticker_id,
$dynamicElements,
$itemCharacteristic,
$serialNumber,
$serNo
);
$tempPdfPath = storage_path('app/temp_sticker_' . uniqid() . '.pdf');
file_put_contents($tempPdfPath, $pdfContent);
exec(
"lp -d " . escapeshellarg($printerName) . " " . escapeshellarg($tempPdfPath),
$output,
$status
);
\Log::info("LP Output:", $output);
\Log::info("LP Status: " . $status);
if ($status != 0) {
Notification::make()
->danger()
->title('Print Failed')
->body("CUPS error while printing.")
->send();
if (file_exists($tempPdfPath)) {
unlink($tempPdfPath);
}
return;
}
if (file_exists($tempPdfPath)) {
unlink($tempPdfPath);
}
}
Notification::make()
->success()
->title('Sticker Printed')
->body("Sticker for Serial Number: $serialNumber printed successfully!")
->seconds(3)
->send();
// [$itemCode, $serialNumber] = explode('|', $serNo);
// $this->dispatch('open-sticker-pdf', [
// 'url' => url("/sticker/pdf/{$itemCode}/{$serialNumber}/$this->plantId/$this->ref_number")
// ]);
}
}
protected function getCupsPrinterNameByIp(string $ip): ?string
{
// exec('lpstat -v 2>&1', $output, $status);
exec('lpstat -h cups:631 -v 2>&1', $output, $status);
if ($status != 0 || empty($output)) {
return null;
}
foreach ($output as $line){
$parts = explode(':', $line, 2);
if (count($parts) < 2) continue;
$printerName = trim(str_replace('device for', '', $parts[0]));
$deviceUri = trim($parts[1]);
if (str_contains($deviceUri, $ip)) {
return $printerName;
}
}
return null;
}
}

View File

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

View File

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

View File

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

View File

@@ -1,276 +0,0 @@
<?php
namespace App\Filament\Resources;
use App\Filament\Resources\VisitorEntryResource\Pages;
use App\Filament\Resources\VisitorEntryResource\RelationManagers;
use App\Models\VisitorEntry;
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;
class VisitorEntryResource extends Resource
{
protected static ?string $model = VisitorEntry::class;
protected static ?string $navigationIcon = 'heroicon-o-rectangle-stack';
public static function form(Form $form): Form
{
return $form
->schema([
Forms\Components\TextInput::make('mobile_number')
->label('Mobile Number')
->length(10)
->reactive()
->extraInputAttributes([
'oninput' => 'this.value = this.value.replace(/[^0-9]/g, "").slice(0, 10)', // blocks non-numbers + limits to 10 chars
'maxlength' => 10,
])
->required()
->extraAttributes([
'id' => 'mobile_number_input',
'x-data' => '{ value: "" }',
'x-model' => 'value',
'wire:keydown.enter.prevent' => 'processMobile(value)',
]),
Forms\Components\TextInput::make('name')
->label('Name')
->required()
->reactive()
->extraInputAttributes([
'oninput' => 'this.value = this.value.replace(/[^a-zA-Z\s]/g, "")',
]),
Forms\Components\Select::make('type')
->label('Type')
->reactive()
->options([
'Student' => 'Student',
'Consultant' => 'Consultant',
'Vendor' => 'Vendor',
'Other' => 'Other',
])
->required()
->dehydrateStateUsing(function ($state, callable $get) {
return $state == 'Other'
? $get('other_type')
: $state;
}),
Forms\Components\TextInput::make('other_type')
->label('Specify Type')
->reactive()
->visible(fn (callable $get) => $get('type') == 'Other')
->required(fn (callable $get) => $get('type') == 'Other')
->dehydrated(false),
Forms\Components\TextInput::make('company')
->label('Company')
->required(),
Forms\Components\Select::make('department')
->label('Employee Department')
->options(
\App\Models\EmployeeMaster::distinct()
->pluck('department', 'department')
)
->required()
->reactive()
->afterStateUpdated(function (callable $set) {
$set('employee_master_id', null);
$set('code', null);
}),
// Forms\Components\Select::make('employee_master_id')
// ->label('Recipient Employee')
// ->required()
// ->options(function (callable $get) {
// $department = $get('department');
// if (!$department) {
// return [];
// }
// return \App\Models\EmployeeMaster::where('department', $department)
// ->pluck('name', 'id');
// })
// ->reactive()
// ->afterStateUpdated(function (callable $set, callable $get, ?string $state) {
// $department = $get('department');
// $employee = \App\Models\EmployeeMaster::where('id', $state)
// ->where('department', $department)
// ->first();
// $set('code', $employee ? $employee->code : '');
// }),
Forms\Components\Select::make('employee_master_id')
->label('Recipient Employee')
->required()
->options(function (callable $get) {
$department = $get('department');
// Always load ALL employees, filter by department if set
if ($department) {
return \App\Models\EmployeeMaster::where('department', $department)
->pluck('name', 'id');
}
// Fallback: load all so fill() can always match the ID
return \App\Models\EmployeeMaster::pluck('name', 'id');
})
->reactive()
->afterStateUpdated(function (callable $set, ?string $state) {
$employee = \App\Models\EmployeeMaster::find($state);
$set('code', $employee?->code ?? '');
}),
Forms\Components\TextInput::make('code')
->label('Employee Code')
->readOnly(),
Forms\Components\Textarea::make('purpose_of_visit')
->label('Purpose of Visit')
->required(),
Forms\Components\TextInput::make('number_of_person')
->numeric()
->default(1)
->required(),
Forms\Components\DateTimePicker::make('in_time')
->label('In Time'),
Forms\Components\DateTimePicker::make('out_time')
->label('Out Time'),
Forms\Components\View::make('components.webcam-field')
->columnSpanFull(),
Forms\Components\Hidden::make('photo'),
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\ImageColumn::make('photo')
->label('Photo')
->disk('public')
->height(50)
->width(50)
// ->defaultImageUrl('https://ui-avatars.com/api/?name=Visitor&background=555&color=fff')
->defaultImageUrl(asset('images/profile.png'))
->alignCenter()
->extraImgAttributes(['style' => 'border-radius: 6px; object-fit: cover;']),
Tables\Columns\TextColumn::make('type')
->label('Visitor Type')
->alignCenter()
->sortable(),
Tables\Columns\TextColumn::make('name')
->label('Visitor Name')
->sortable()
->alignCenter()
->searchable(),
Tables\Columns\TextColumn::make('mobile_number')
->label('Visitor Mobile Number')
->alignCenter()
->sortable(),
Tables\Columns\TextColumn::make('employeeMaster.name')
->label('Recipient Name')
->alignCenter()
->sortable(),
Tables\Columns\TextColumn::make('employeeMaster.code')
->label('Receipient ID')
->alignCenter()
->sortable(),
Tables\Columns\TextColumn::make('employeeMaster.department')
->label('Receipient Department')
->alignCenter()
->sortable(),
Tables\Columns\TextColumn::make('number_of_person')
->label('Number of Person')
->numeric()
->alignCenter()
->sortable(),
Tables\Columns\TextColumn::make('in_time')
->label('In Time')
->dateTime()
->sortable()
->alignCenter(),
Tables\Columns\TextColumn::make('out_time')
->label('Out Time')
->dateTime()
->sortable()
->alignCenter(),
Tables\Columns\TextColumn::make('created_at')
->label('Created At')
->dateTime()
->sortable()
->toggleable(isToggledHiddenByDefault: true)
->alignCenter(),
Tables\Columns\TextColumn::make('updated_at')
->label('Updated At')
->dateTime()
->sortable()
->toggleable(isToggledHiddenByDefault: true)
->alignCenter(),
Tables\Columns\TextColumn::make('deleted_at')
->label('Deleted At')
->dateTime()
->sortable()
->toggleable(isToggledHiddenByDefault: true)
->alignCenter(),
])
->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\ListVisitorEntries::route('/'),
'create' => Pages\CreateVisitorEntry::route('/create'),
'view' => Pages\ViewVisitorEntry::route('/{record}'),
'edit' => Pages\EditVisitorEntry::route('/{record}/edit'),
];
}
public static function getEloquentQuery(): Builder
{
return parent::getEloquentQuery()
->withoutGlobalScopes([
SoftDeletingScope::class,
]);
}
}

View File

@@ -1,150 +0,0 @@
<?php
namespace App\Filament\Resources\VisitorEntryResource\Pages;
use App\Filament\Resources\VisitorEntryResource;
use App\Models\EmployeeMaster;
use App\Models\VisitorEntry;
use Filament\Actions;
use Filament\Resources\Pages\CreateRecord;
use Livewire\Attributes\On;
use Storage;
class CreateVisitorEntry extends CreateRecord
{
protected static string $resource = VisitorEntryResource::class;
public $capturedPhoto;
// #[On('photo-captured')]
// public function handlePhotoCapture(string $photo): void
// {
// // Puts the Base64 photo into the form's data array
// $this->data['photo'] = $photo;
// }
public function processMobile($mobile)
{
$visitor = VisitorEntry::where('mobile_number', $mobile)->latest()->first();
if ($visitor) {
$employee = EmployeeMaster::where('id', $visitor->employee_master_id)->first();
$this->form->fill([
'mobile_number' => $mobile ?? '',
'name' => $visitor->name ?? '',
'company' => $visitor->company ?? '',
'type' => $visitor->type ?? '',
'department' => $employee->department ?? '',
'employee_master_id' => $visitor->employee_master_id->name ?? '',
'code' => $employee->code ?? '',
]);
}
else {
$this->form->fill([
'mobile_number' => $mobile ?? '',
'name' => $visitor->name ?? '',
'company' => $visitor->company ?? '',
'type' => $visitor->type ?? '',
'department' => $employee->department ?? '',
'employee_master_id' => $visitor->employee_master_id->name ?? '',
'code' => $employee->code ?? '',
]);
}
}
// protected function mutateFormDataBeforeCreate(array $data): array
// {
// if (
// !empty($data['photo']) &&
// str_starts_with($data['photo'], 'data:image')
// ) {
// // Step A: Strip the "data:image/jpeg;base64," prefix
// $imageData = explode(',', $data['photo'])[1];
// // Step B: Generate a unique filename
// $filename = 'visitor_' . time() . '_' . uniqid() . '.jpg';
// // Step C: Decode Base64 and save as a real .jpg file
// $path = 'visitor-photos/' . $filename;
// Storage::disk('public')->put($path, base64_decode($imageData));
// // Step D: Replace the Base64 string with just the file path
// $data['photo'] = $path;
// }
// return $data;
// }
#[On('photo-captured')]
public function handlePhotoCapture(string $photo): void
{
$this->data['photo'] = $photo;
\Log::info('WEBCAM: photo-captured event received, length: ' . strlen($photo));
}
// protected function mutateFormDataBeforeCreate(array $data): array
// {
// \Log::info('WEBCAM: mutateFormDataBeforeCreate called, photo value: ' . substr($data['photo'] ?? 'NULL', 0, 50));
// if (
// !empty($data['photo']) &&
// str_starts_with($data['photo'], 'data:image')
// ) {
// $imageData = explode(',', $data['photo'])[1];
// $filename = 'visitor_' . time() . '_' . uniqid() . '.jpg';
// $path = 'visitor-photos/' . $filename;
// Storage::disk('public')->put($path, base64_decode($imageData));
// $data['photo'] = $path;
// \Log::info('WEBCAM: photo saved to ' . $path);
// }
// return $data;
// }
protected function mutateFormDataBeforeCreate(array $data): array
{
if (
!empty($data['photo']) &&
str_starts_with($data['photo'], 'data:image')
) {
try {
$imageData = explode(',', $data['photo'])[1];
$filename = 'visitor_' . time() . '_' . uniqid() . '.jpg';
$path = 'visitor-photos/' . $filename;
$decoded = base64_decode($imageData);
$saved = Storage::disk('public')->put($path, $decoded);
\Log::info('PHOTO UPLOAD (PUBLIC):', [
'filename' => $filename,
'path' => $path,
'size_bytes' => strlen($decoded),
'saved' => $saved ? 'SUCCESS' : 'FAILED',
]);
$data['photo'] = $path;
} catch (\Exception $e) {
\Log::error('PHOTO UPLOAD ERROR: ' . $e->getMessage());
}
}
return $data;
}
public function setPhoto(string $photo): void
{
$this->capturedPhoto = $photo;
// Change this ↓ to dispatch to parent explicitly
$this->dispatch('photo-captured', photo: $photo)->to(\App\Filament\Resources\VisitorEntryResource\Pages\CreateVisitorEntry::class);
}
}

View File

@@ -1,54 +0,0 @@
<?php
namespace App\Filament\Resources\VisitorEntryResource\Pages;
use App\Filament\Resources\VisitorEntryResource;
use Filament\Actions;
use Filament\Resources\Pages\EditRecord;
use Livewire\Attributes\On;
use Storage;
class EditVisitorEntry extends EditRecord
{
protected static string $resource = VisitorEntryResource::class;
protected function getHeaderActions(): array
{
return [
Actions\ViewAction::make(),
Actions\DeleteAction::make(),
Actions\ForceDeleteAction::make(),
Actions\RestoreAction::make(),
];
}
#[On('photo-captured')]
public function handlePhotoCapture(string $photo): void
{
$this->data['photo'] = $photo;
}
protected function mutateFormDataBeforeSave(array $data): array
{
if (
!empty($data['photo']) &&
str_starts_with($data['photo'], 'data:image')
) {
// Delete the old photo file if one exists
$oldPhoto = $this->record->photo;
if ($oldPhoto && Storage::disk('public')->exists($oldPhoto)) {
Storage::disk('public')->delete($oldPhoto);
}
// Save the new photo
$imageData = explode(',', $data['photo'])[1];
$filename = 'visitor_' . time() . '_' . uniqid() . '.jpg';
$path = 'visitor-photos/' . $filename;
Storage::disk('public')->put($path, base64_decode($imageData));
$data['photo'] = $path;
}
return $data;
}
}

View File

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

View File

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

View File

@@ -1,146 +0,0 @@
<?php
namespace App\Filament\Widgets;
use App\Models\RequestQuotation;
use App\Models\RfqTransporterBid;
use Filament\Facades\Filament;
use Filament\Widgets\StatsOverviewWidget as BaseWidget;
use Filament\Widgets\StatsOverviewWidget\Stat;
class RfqChart extends BaseWidget
{
// protected function getStats(): array
// {
// $transporter = session('transport_name');
// $rfqNumber = session('rfq_number');
// if (!$transporter || !$rfqNumber) {
// return [
// Stat::make('Total Freight Charge', '-'),
// Stat::make('Rank', '-'),
// ];
// }
// $selectedRfq = RequestQuotation::query()
// ->where('transporter_name', $transporter)
// ->where('rfq_number', $rfqNumber)
// ->first();
// if (!$selectedRfq) {
// return [
// Stat::make('Total Freight Charge', '-'),
// Stat::make('Rank', '-'),
// ];
// }
// $myAmount = (float) $selectedRfq->total_freight_charge;
// $rank = RequestQuotation::query()
// ->whereRaw(
// 'CAST(total_freight_charge AS DECIMAL(10,2)) < ?',
// [$myAmount]
// )
// ->selectRaw('CAST(total_freight_charge AS DECIMAL(10,2))')
// ->distinct()
// ->count() + 1;
// $medal = match (true) {
// $rank == 1 => '🥇',
// $rank == 2 => '🥈',
// $rank == 3 => '🥉',
// default => '',
// };
// return [
// Stat::make(
// 'Total Freight Charge',
// number_format($selectedRfq->total_freight_charge, 2)
// )
// ->description('Transporter: ' . $selectedRfq->transporter_name)
// ->color($rank == 1 ? 'success' : 'primary'),
// Stat::make(
// 'Rank',
// trim("{$medal} #{$rank}")
// )
// ->description('Among all transporters')
// ->color(
// $rank == 1 ? 'success' :
// ($rank <= 3 ? 'warning' : 'gray')
// ),
// ];
// }
protected function getStats(): array
{
$transporter = session('transport_name');
$rfqNumber = session('rfq_id');
if (!$transporter || !$rfqNumber) {
return [
Stat::make('Total Freight Charge', '-'),
Stat::make('Rank', '-'),
];
}
$selectedRfq = RfqTransporterBid::query()
->where('transporter_name', $transporter)
->where('request_quotation_id', $rfqNumber)
->first();
if (!$selectedRfq) {
return [
Stat::make('Total Freight Charge', '-'),
Stat::make('Rank', '-'),
];
}
$myAmount = (float) $selectedRfq->total_freight_charge;
// $rank = RfqTransporterBid::query()
// ->whereRaw(
// 'CAST(total_freight_charge AS DECIMAL(10,2)) < ?',
// [$myAmount]
// )
// ->selectRaw('CAST(total_freight_charge AS DECIMAL(10,2))')
// ->distinct()
// ->count() + 1;
$rank = RfqTransporterBid::query()
->where('request_quotation_id', $rfqNumber) // 🔥 MISSING CONDITION
->whereRaw(
'CAST(total_freight_charge AS DECIMAL(10,2)) < ?',
[$myAmount]
)
->selectRaw('CAST(total_freight_charge AS DECIMAL(10,2))')
->distinct()
->count() + 1;
$medal = match (true) {
$rank == 1 => '🥇',
$rank == 2 => '🥈',
$rank == 3 => '🥉',
default => '',
};
return [
Stat::make(
'Total Freight Charge',
number_format($selectedRfq->total_freight_charge, 2)
)
->description('Transporter: ' . $selectedRfq->transporter_name)
->color($rank == 1 ? 'success' : 'primary'),
Stat::make(
'Rank',
trim("{$medal} #{$rank}")
)
->description('Among all transporters')
->color(
$rank == 1 ? 'success' :
($rank <= 3 ? 'warning' : 'gray')
),
];
}
}

View File

@@ -1,205 +0,0 @@
<?php
namespace App\Filament\Widgets;
use App\Models\RfqTransporterBid;
use Filament\Widgets\ChartWidget;
use Illuminate\Support\Js;
class RfqRankChart extends ChartWidget
{
protected static ?string $heading = 'Chart';
// protected function getData(): array
// {
// $rfqId = session('rfq_id');
// if (!$rfqId) {
// return [
// 'datasets' => [],
// 'labels' => [],
// ];
// }
// // Get bids ordered by lowest freight charge
// $bids = RfqTransporterBid::query()
// ->where('request_quotation_id', $rfqId)
// ->orderByRaw('CAST(total_freight_charge AS DECIMAL(10,2)) ASC')
// ->get();
// // $labels = [];
// // $ranks = [];
// // $rank = 1;
// // foreach ($bids as $bid) {
// // $labels[] = $bid->transporter_name;
// // $ranks[] = $rank++;
// // }
// // return [
// // 'datasets' => [
// // [
// // 'label' => 'Rank (Lower is Better)',
// // 'data' => $ranks,
// // 'fill' => false,
// // 'tension' => 0.3,
// // ],
// // ],
// // 'labels' => $labels,
// // ];
// $labels = [];
// $ranks = [];
// $colors = [];
// $rank = 1;
// foreach ($bids as $bid) {
// $labels[] = $bid->transporter_name;
// $ranks[] = $rank;
// // Rank-based colors
// $colors[] = match ($rank) {
// 1 => '#FFD700', // Gold
// 2 => '#C0C0C0', // Silver
// 3 => '#CD7F32', // Bronze
// default => '#3B82F6', // Blue
// };
// $rank++;
// }
// return [
// 'datasets' => [
// [
// 'label' => 'Rank (1 = Best)',
// 'data' => $ranks,
// // 🎨 Styling
// 'borderColor' => '#3B82F6',
// 'backgroundColor' => $colors,
// 'pointBackgroundColor' => $colors,
// 'pointBorderColor' => '#000',
// 'pointRadius' => 7,
// 'pointHoverRadius' => 10,
// 'borderWidth' => 3,
// 'tension' => 0.4,
// 'fill' => false,
// ],
// ],
// 'labels' => $labels,
// ];
// }
protected function getData(): array
{
$rfqId = session('rfq_id');
if (!$rfqId) {
return [
'datasets' => [],
'labels' => [],
];
}
/**
* STEP 1: Get bids sorted by freight charge (for ranking)
*/
$rankedBids = RfqTransporterBid::query()
->where('request_quotation_id', $rfqId)
->orderByRaw('CAST(total_freight_charge AS DECIMAL(10,2)) ASC')
->get();
$rankMap = [];
$rank = 1;
foreach ($rankedBids as $bid) {
$rankMap[$bid->id] = $rank++;
}
/**
* STEP 2: Get bids in natural order (for wave effect)
* You can change orderBy to:
* - created_at
* - transporter_name
*/
$chartBids = RfqTransporterBid::query()
->where('request_quotation_id', $rfqId)
->orderBy('id')
->get();
$labels = [];
$amounts = [];
$colors = [];
$ranks = [];
foreach ($chartBids as $bid) {
$labels[] = $bid->transporter_name;
$amounts[] = (float) $bid->total_freight_charge;
$rank = $rankMap[$bid->id];
$ranks[] = $rank;
$colors[] = match ($rank) {
1 => '#FFD700',
2 => '#C0C0C0',
3 => '#CD7F32',
default => '#2563EB',
};
}
return [
'datasets' => [
[
'label' => 'Freight Charge',
'data' => $amounts,
'rankData' => $ranks,
'borderColor' => '#2563EB',
'backgroundColor' => $colors,
'pointBackgroundColor' => $colors,
'pointBorderColor' => '#000',
'pointRadius' => 7,
'pointHoverRadius' => 11,
'borderWidth' => 3,
'tension' => 0.45,
'fill' => false,
],
],
'labels' => $labels,
];
}
protected function getOptions(): array
{
return [
'plugins' => [
'datalabels' => [
'anchor' => 'start',
'align' => 'start',
'offset' => -15,
'color' => '#000',
'font' => [
'weight' => 'bold',
],
'formatter' => Js::from("function(value) { return Number(value); }"),
],
],
'scales' => [
'y' => [
'beginAtZero' => true,
'ticks' => [
'stepSize' => 0.5,
],
],
],
];
}
protected function getType(): string
{
return 'bar';
}
}

View File

@@ -4,14 +4,9 @@ namespace App\Http\Controllers;
use App\Models\GrMaster;
use App\Models\Item;
use App\Models\ItemCharacteristic;
use App\Models\Plant;
use App\Models\ProcessOrder;
use App\Models\StickerDetail;
use App\Models\StickerStructureDetail;
use App\Models\User;
use App\Services\StickerPdfService;
use Filament\Notifications\Notification;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Log;
use Illuminate\Support\Facades\Response;
@@ -894,155 +889,4 @@ class PdfController extends Controller
{
//
}
// public function generate(string $stickerId)
// {
// $stickerId = trim($stickerId);
// $elements = StickerStructureDetail::where('sticker_id', $stickerId)
// ->first();
// $pdfService = new StickerPdfService();
// return $pdfService->generate($stickerId, $elements->toArray());
// }
public function generate(Request $request, $stickerId)
{
$plantId = $request->query('plant_id');
$itemCharacteristicId = $request->query('item_characteristic_id');
$stickerId = trim($stickerId);
//dd($plantId,$itemCharacteristicId,$stickerId);
// Normalize "empty" or "" to null
$plantId = ($plantId && $plantId != 'empty') ? $plantId : null;
$itemCharacteristicId = ($itemCharacteristicId && $itemCharacteristicId != 'empty') ? $itemCharacteristicId : null;
if ($plantId && $itemCharacteristicId)
{
$plantId = $request->query('plant_id');
$itemCharacteristicId = $request->query('item_characteristic_id');
$sticId = StickerStructureDetail::where('sticker_id', $stickerId)->first();
$sId = $sticId->id;
$dynamicElements = StickerDetail::where('sticker_structure_detail_id', $sId)
->where('element_type', 'Dynamic')
->get();
$itemCharacteristic = null;
if ($plantId && $itemCharacteristicId) {
$itemCharacteristic = ItemCharacteristic::where('plant_id', $plantId)
->where('id', $itemCharacteristicId)
->first();
}
$pdfService = new StickerPdfService();
return $pdfService->generate1(
$stickerId,
$dynamicElements,
$itemCharacteristic
);
}
else
{
$elements = StickerStructureDetail::where('sticker_id', $stickerId)
->first();
$pdfService = new StickerPdfService();
return $pdfService->generate($stickerId, $elements->toArray());
}
}
// public function generatePdf(Request $request, $stickerId)
// {
// $plantId = $request->query('plant_id');
// $itemCharacteristicId = $request->query('item_characteristic_id');
// $stickerId = trim($stickerId);
// //dd($plantId,$itemCharacteristicId,$stickerId);
// // Normalize "empty" or "" to null
// $plantId = ($plantId && $plantId != 'empty') ? $plantId : null;
// $itemCharacteristicId = ($itemCharacteristicId && $itemCharacteristicId != 'empty') ? $itemCharacteristicId : null;
// if ($plantId && $itemCharacteristicId)
// {
// $plantId = $request->query('plant_id');
// $itemCharacteristicId = $request->query('item_characteristic_id');
// $sticId = StickerStructureDetail::where('id', $stickerId)->first();
// $sId = $sticId->id;
// $stickerId = $sticId->sticker_id;
// $dynamicElements = StickerDetail::where('sticker_structure_detail_id', $sId)
// ->where('element_type', 'Dynamic')
// ->get();
// $itemCharacteristic = null;
// if ($plantId && $itemCharacteristicId) {
// $itemCharacteristic = ItemCharacteristic::where('plant_id', $plantId)
// ->where('id', $itemCharacteristicId)
// ->first();
// }
// $pdfService = new StickerPdfService();
// return $pdfService->generatePdf1(
// $stickerId,
// $dynamicElements,
// $itemCharacteristic
// );
// }
// else
// {
// $elements = StickerStructureDetail::where('sticker_id', $stickerId)
// ->first();
// $pdfService = new StickerPdfService();
// return $pdfService->generate($stickerId, $elements->toArray());
// }
// }
public function generatePdf(Request $request, $stickerId)
{
$plantId = $request->query('plant_id');
$itemCharacteristicId = $request->query('item_characteristic_id');
$serialNumber = $request->query('serial_number');
if ($plantId && $itemCharacteristicId) {
$structure = StickerStructureDetail::findOrFail($stickerId);
$dynamicElements = StickerDetail::where(
'sticker_structure_detail_id',
$structure->id
)->where('element_type', 'Dynamic')->get();
$itemCharacteristic = ItemCharacteristic::where('plant_id', $plantId)
->where('id', $itemCharacteristicId)
->first();
return (new StickerPdfService())->generatePdf1(
$structure->sticker_id,
$dynamicElements,
$itemCharacteristic,
$serialNumber
);
}
return abort(404);
}
}

View File

@@ -1,482 +0,0 @@
<?php
namespace App\Livewire;
use App\Services\ChatbotService;
use App\Services\GeminiChatbotService;
use Livewire\Component;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Log;
class ChatBot extends Component
{
// ── Panel state ───────────────────────────────────────────────────────────
public bool $isOpen = false;
/**
* 'select' mode-picker screen shown first
* 'basic' structured query UI (production or invoice report)
* 'advanced' free-text natural-language UI (Gemini-powered)
*/
public string $mode = 'select';
// ── Basic mode — shared ───────────────────────────────────────────────────
/**
* Which report the user picked inside basic mode.
* '' report-type picker shown
* 'production' production form
* 'invoice' invoice type-lookup form
* 'invoice_status' invoice scan-status form
*/
public string $reportType = '';
public array $plants = [];
// ── Basic mode — Production report ───────────────────────────────────────
public string $result = '';
public bool $hasResult = false;
public ?int $selectedPlantId = null;
public ?int $selectedLineId = null;
public string $dateFrom = '';
public string $dateTo = '';
public array $lines = [];
// ── Basic mode — Invoice report (type lookup) ─────────────────────────────
public ?int $invoicePlantId = null;
public string $invoiceItemCode = '';
public string $invoiceResult = '';
public bool $hasInvoiceResult = false;
// ── Basic mode — Invoice status (scan status) ─────────────────────────────
public string $invoiceNumber = '';
public string $invoiceStatusResult = ''; // kept for simple error strings
public bool $hasInvoiceStatusResult = false;
/**
* Structured result from ChatbotService::getInvoiceData().
* Shape: type, message, invoice_number, total, scanned, not_scanned, unscanned_serials[]
*/
public array $invoiceStatusData = [];
/** Controls whether all unscanned serials are shown (vs the first 10). */
public bool $showAllUnscanned = false;
// ── Advanced mode ─────────────────────────────────────────────────────────
public string $advancedQuestion = '';
public string $advancedResult = '';
public bool $hasAdvancedResult = false;
public bool $isAdvancedLoading = false;
/**
* Conversation history shown in advanced mode.
* Each entry: ['role' => 'user'|'assistant', 'content' => '…']
*
* The full history is passed to GeminiChatbotService on every turn so
* Gemini can resolve follow-up messages (e.g. answering a clarification
* question) in context.
*/
public array $chatHistory = [];
// ─────────────────────────────────────────────────────────────────────────
public function mount(): void
{
$this->plants = DB::table('plants')
->whereNull('deleted_at')
->orderBy('name')
->get(['id', 'name'])
->toArray();
$this->dateFrom = now()->startOfMonth()->format('Y-m-d');
$this->dateTo = now()->format('Y-m-d');
}
// ── Mode switching ────────────────────────────────────────────────────────
public function setMode(string $mode): void
{
$this->mode = $mode;
}
public function setReportType(string $type): void
{
$this->reportType = $type;
// Clear previous results when switching report type
$this->result = '';
$this->hasResult = false;
$this->invoiceResult = '';
$this->hasInvoiceResult = false;
$this->invoiceStatusResult = '';
$this->hasInvoiceStatusResult = false;
$this->invoiceStatusData = [];
$this->showAllUnscanned = false;
}
// ── Basic mode — Production helpers ──────────────────────────────────────
public function updatedSelectedPlantId(): void
{
$this->selectedLineId = null;
$this->lines = [];
$this->result = '';
$this->hasResult = false;
if ($this->selectedPlantId) {
$this->lines = DB::table('lines')
->whereNull('deleted_at')
->where('plant_id', $this->selectedPlantId)
->orderBy('name')
->get(['id', 'name'])
->toArray();
}
}
public function updatedSelectedLineId(): void
{
$this->result = '';
$this->hasResult = false;
}
public function fetchProduction(): void
{
if (! $this->selectedPlantId) {
$this->result = 'Please select a plant.';
$this->hasResult = true;
return;
}
$query = DB::table('production_quantities')
->whereNull('deleted_at')
->where('plant_id', $this->selectedPlantId)
->whereDate('created_at', '>=', $this->dateFrom)
->whereDate('created_at', '<=', $this->dateTo);
if ($this->selectedLineId) {
$query->where('line_id', $this->selectedLineId);
}
$count = $query->count();
$plantName = collect($this->plants)
->firstWhere('id', $this->selectedPlantId)?->name ?? 'Unknown Plant';
$lineName = $this->selectedLineId
? (collect($this->lines)->firstWhere('id', $this->selectedLineId)?->name ?? 'Unknown Line')
: 'All Lines';
$from = \Carbon\Carbon::parse($this->dateFrom)->format('d M Y');
$to = \Carbon\Carbon::parse($this->dateTo)->format('d M Y');
$this->result = "Production count for {$plantName} / {$lineName} from {$from} to {$to}: {$count} records.";
$this->hasResult = true;
}
// ── Basic mode — Invoice report (type lookup) ─────────────────────────────
public function updatedInvoicePlantId(): void
{
$this->invoiceResult = '';
$this->hasInvoiceResult = false;
}
public function updatedInvoiceItemCode(): void
{
$this->invoiceResult = '';
$this->hasInvoiceResult = false;
}
public function fetchInvoiceReport(): void
{
if (! $this->invoicePlantId) {
$this->invoiceResult = 'Please select a plant.';
$this->hasInvoiceResult = true;
return;
}
$itemCode = trim($this->invoiceItemCode);
if ($itemCode === '') {
$this->invoiceResult = 'Please enter an item code.';
$this->hasInvoiceResult = true;
return;
}
$plantName = collect($this->plants)
->firstWhere('id', $this->invoicePlantId)?->name ?? 'Unknown Plant';
try {
$rows = DB::select("
WITH plant_item AS (
SELECT ? AS user_plant,
? AS user_item_code
),
t1 AS (
SELECT
plants.id AS plant_id,
plants.name AS plant_name,
ARRAY_AGG(items.code) AS item_codes
FROM plants
LEFT JOIN items ON plants.id = items.plant_id
GROUP BY plants.id, plants.name
),
t2 AS (
SELECT
t1.plant_id,
t1.plant_name,
CASE
WHEN plant_item.user_item_code = ANY(t1.item_codes) THEN 1
ELSE 0
END AS exists_flag
FROM t1
CROSS JOIN plant_item
WHERE t1.plant_name = plant_item.user_plant
),
t3 AS (
SELECT t2.plant_id, t2.plant_name, t2.exists_flag,
plant_item.user_item_code
FROM t2
LEFT JOIN plant_item ON plant_item.user_plant = t2.plant_name
),
t4 AS (
SELECT items.id AS item_id,
t3.plant_id, t3.plant_name, t3.exists_flag, t3.user_item_code
FROM t3
LEFT JOIN items
ON t3.plant_id = items.plant_id
AND t3.user_item_code = items.code
)
SELECT
t4.item_id,
t4.plant_id,
t4.plant_name,
t4.exists_flag,
t4.user_item_code,
COALESCE(sticker_masters.material_type, 0) AS material_type,
CASE
WHEN sticker_masters.item_id IS NULL
THEN 'no match found'
WHEN COALESCE(sticker_masters.material_type, 0) = 0
THEN 'serial invoice'
ELSE 'material invoice'
END AS invoice_description
FROM t4
LEFT JOIN sticker_masters
ON sticker_masters.plant_id = t4.plant_id
AND sticker_masters.item_id = t4.item_id
", [$plantName, $itemCode]);
} catch (\Exception $e) {
Log::error('ChatBot: invoice report query failed', [
'plant' => $plantName,
'item_code' => $itemCode,
'error' => $e->getMessage(),
]);
$this->invoiceResult = "Sorry, I couldn't fetch data. Please try again or contact support.";
$this->hasInvoiceResult = true;
return;
}
if (empty($rows)) {
$this->invoiceResult = "No data found for plant \"{$plantName}\". Please verify the plant selection.";
$this->hasInvoiceResult = true;
return;
}
$row = $rows[0];
if ((int) $row->exists_flag === 0) {
$this->invoiceResult = 'Provided item code does not exist in the item table.';
} else {
switch ($row->invoice_description) {
case 'no match found':
$this->invoiceResult = "Item not found in sticker master for the plant {$row->plant_name}.";
break;
case 'serial invoice':
$this->invoiceResult = 'It is a serial invoice item.';
break;
case 'material invoice':
$this->invoiceResult = 'It is a material invoice item.';
break;
default:
$this->invoiceResult = 'Unexpected result. Please contact support.';
}
}
$this->hasInvoiceResult = true;
}
// ── Basic mode — Invoice status (scan status) ─────────────────────────────
public function updatedInvoiceNumber(): void
{
$this->invoiceStatusResult = '';
$this->hasInvoiceStatusResult = false;
$this->invoiceStatusData = [];
$this->showAllUnscanned = false;
}
/**
* Looks up how many serials within an invoice have been scanned / not scanned.
* Stores structured data in $invoiceStatusData so the blade can render
* a "show more" serial-number list without dumping 70+ serials in one blob.
*/
public function fetchInvoiceStatus(): void
{
$invoiceNumber = trim(preg_replace('/\s+/', '', $this->invoiceNumber));
if (empty($invoiceNumber)) {
$this->invoiceStatusResult = 'Please enter a valid invoice number.';
$this->invoiceStatusData = [];
$this->showAllUnscanned = false;
$this->hasInvoiceStatusResult = true;
return;
}
try {
/** @var \App\Services\ChatbotService $service */
$service = app(\App\Services\ChatbotService::class);
$data = $service->getInvoiceData($invoiceNumber);
} catch (\Throwable $e) {
Log::error('ChatBot: invoice status fetch failed', [
'invoice' => $invoiceNumber,
'error' => $e->getMessage(),
]);
$data = [
'type' => 'error',
'message' => "Sorry, I couldn't fetch data for invoice {$invoiceNumber}. "
. 'Please try again or contact support.',
'invoice_number' => $invoiceNumber,
'total' => 0,
'scanned' => 0,
'not_scanned' => 0,
'unscanned_serials' => [],
];
}
$this->invoiceStatusData = $data;
$this->invoiceStatusResult = $data['message']; // fallback plain-text copy
$this->showAllUnscanned = false;
$this->hasInvoiceStatusResult = true;
}
/**
* Toggles the "show all / show less" state for unscanned serial numbers
* in the Basic Invoice Status result card.
*/
public function toggleShowAllUnscanned(): void
{
$this->showAllUnscanned = ! $this->showAllUnscanned;
}
// ── Advanced mode (Gemini-powered) ────────────────────────────────────────
/**
* Handles a free-text user message in advanced mode.
*
* Steps:
* 1. Appends the user message to chatHistory immediately (UI feedback).
* 2. Calls GeminiChatbotService with the full prior history for context.
* 3. Gemini classifies the intent, extracts params, and either:
* a) runs the appropriate DB query and returns the result, or
* b) returns a clarification question if intent is ambiguous.
* 4. Appends the assistant reply to chatHistory.
*/
public function askAdvanced(): void
{
$question = trim($this->advancedQuestion);
if (empty($question)) {
return;
}
// Show the user's message in the chat bubble immediately
$this->chatHistory[] = [
'role' => 'user',
'content' => $question,
];
$this->advancedQuestion = '';
$this->isAdvancedLoading = true;
try {
/** @var GeminiChatbotService $gemini */
$gemini = app(GeminiChatbotService::class);
// Pass history *without* the turn we just appended — the new user
// message is passed separately so Gemini sees it as the latest turn.
$priorHistory = array_slice($this->chatHistory, 0, -1);
$answer = $gemini->processMessage($priorHistory, $question);
} catch (\Throwable $e) {
Log::error('ChatBot: advanced ask failed', [
'error' => $e->getMessage(),
'trace' => $e->getTraceAsString(),
]);
$answer = 'Sorry, something went wrong. Please try again.';
}
$this->chatHistory[] = [
'role' => 'assistant',
'content' => $answer,
];
$this->isAdvancedLoading = false;
}
public function clearAdvancedChat(): void
{
$this->chatHistory = [];
$this->advancedQuestion = '';
$this->isAdvancedLoading = false;
}
// ── Panel controls ────────────────────────────────────────────────────────
public function toggleChat(): void
{
$this->isOpen = ! $this->isOpen;
}
public function resetForm(): void
{
// Basic mode — shared
$this->reportType = '';
// Basic mode — production
$this->selectedPlantId = null;
$this->selectedLineId = null;
$this->lines = [];
$this->result = '';
$this->hasResult = false;
$this->dateFrom = now()->startOfMonth()->format('Y-m-d');
$this->dateTo = now()->format('Y-m-d');
// Basic mode — invoice type lookup
$this->invoicePlantId = null;
$this->invoiceItemCode = '';
$this->invoiceResult = '';
$this->hasInvoiceResult = false;
// Basic mode — invoice scan status
$this->invoiceNumber = '';
$this->invoiceStatusResult = '';
$this->hasInvoiceStatusResult = false;
$this->invoiceStatusData = [];
$this->showAllUnscanned = false;
// Advanced mode
$this->clearAdvancedChat();
// Go back to mode selector
$this->mode = 'select';
}
public function render()
{
return view('livewire.chat-bot');
}
}

View File

@@ -1,236 +0,0 @@
<?php
namespace App\Livewire;
use App\Exports\ProductionPlanExport;
use App\Models\ProductionPlan;
use App\Models\ProductionQuantity;
use Livewire\Component;
use Carbon\Carbon;
use DB;
use Maatwebsite\Excel\Facades\Excel;
class ProductionTargetPlan extends Component
{
public $plantId, $lineId, $month, $year;
public $records = [];
public $dates = [];
public $leaveDates = [];
public $productionPlanDates = '';
protected $listeners = [
'loadData' => 'loadProductionData',
'loadData1' => 'exportProductionData',
];
public function getMonthDates($month, $year)
{
$start = Carbon::createFromDate($year, $month, 1);
$days = $start->daysInMonth;
$dates = [];
for ($i = 1; $i <= $days; $i++) {
$dates[] = Carbon::createFromDate($year, $month, $i)
->format('Y-m-d');
}
return $dates;
}
public function loadProductionData($plantId, $lineId, $month, $year){
if (!$plantId || !$lineId || !$month || !$year) {
$this->records = [];
$this->dates = [];
$this->leaveDates = [];
return;
}
$this->dates = $this->getMonthDates($month, $year);
$data = ProductionPlan::query()
->join('items', 'items.id', '=', 'production_plans.item_id')
->join('lines', 'lines.id', '=', 'production_plans.line_id')
->join('plants', 'plants.id', '=', 'production_plans.plant_id')
->where('production_plans.plant_id', $plantId)
->where('production_plans.line_id', $lineId)
->whereMonth('production_plans.created_at', $month)
->whereYear('production_plans.created_at', $year)
->select(
'production_plans.created_at',
'production_plans.operator_id',
'plants.name as plant',
'items.code as item_code',
'items.description as item_description',
'lines.name as line_name',
'production_plans.leave_dates'
)
->first();
if ($data && $data->leave_dates) {
$this->leaveDates = array_map('trim', explode(',', $data->leave_dates));
}
$producedData = ProductionQuantity::selectRaw("
plant_id,
line_id,
item_id,
DATE(created_at) as prod_date,
COUNT(*) as total_qty
")
->where('plant_id', $plantId)
->where('line_id', $lineId)
->whereMonth('created_at', $month)
->whereYear('created_at', $year)
->groupBy('plant_id', 'line_id', 'item_id', DB::raw('DATE(created_at)'))
->get()
->groupBy(function ($row) {
return $row->plant_id . '_' . $row->line_id . '_' . $row->item_id;
})
->map(function ($group) {
return $group->keyBy('prod_date');
});
$this->records = ProductionPlan::query()
->join('items', 'items.id', '=', 'production_plans.item_id')
->join('lines', 'lines.id', '=', 'production_plans.line_id')
->join('plants', 'plants.id', '=', 'production_plans.plant_id')
->where('production_plans.plant_id', $plantId)
->where('production_plans.line_id', $lineId)
->whereMonth('production_plans.created_at', $month)
->whereYear('production_plans.created_at', $year)
->select(
'production_plans.item_id',
'production_plans.plant_id',
'production_plans.line_id',
'production_plans.plan_quantity',
'production_plans.working_days',
'items.code as item_code',
'items.description as item_description',
'lines.name as line_name',
'plants.name as plant_name'
)
->get()
// ->map(function ($row) use ($producedData) {
// $row = $row->toArray();
// $row['daily_target'] = ($row['working_days'] > 0)
// ? round($row['plan_quantity'] / $row['working_days'], 2)
// : 0;
// // $key = $row['plant_id'].'_'.$row['line_id'].'_'.$row['item_id'];
// // foreach ($this->dates as $date) {
// // $found = $producedData[$key][$date] ?? null;
// // $row['produced_quantity'][$date] = $found->total_qty ?? 0;
// // }
// $remainingDays = $row['working_days'];
// $pendingQty = 0;
// $row['daily_target_dynamic'] = [];
// $row['produced_quantity'] = [];
// $key = $row['plant_id'].'_'.$row['line_id'].'_'.$row['item_id'];
// foreach ($this->dates as $date) {
// $found = $producedData[$key][$date] ?? null;
// $producedQty = $found->total_qty ?? 0;
// // today's adjusted target
// $todayTarget = $baseDailyTarget;
// if ($remainingDays > 1 && $pendingQty > 0) {
// $todayTarget += $pendingQty / $remainingDays;
// }
// $row['daily_target_dynamic'][$date] = round($todayTarget, 2);
// $row['produced_quantity'][$date] = $producedQty;
// // calculate today's shortfall
// $pendingQty += ($todayTarget - $producedQty);
// if ($pendingQty < 0) {
// $pendingQty = 0;
// }
// $remainingDays--;
// }
// return $row;
// })
->map(function ($row) use ($producedData) {
$row = $row->toArray();
$remainingQty = $row['plan_quantity'];
$remainingDays = $row['working_days'];
$row['daily_target_dynamic'] = [];
$row['produced_quantity'] = [];
$key = $row['plant_id'].'_'.$row['line_id'].'_'.$row['item_id'];
foreach ($this->dates as $date) {
// Skip leave dates
if (in_array($date, $this->leaveDates)) {
$row['daily_target_dynamic'][$date] = '-';
$row['produced_quantity'][$date] = '-';
continue;
}
$todayTarget = $remainingDays > 0
? round($remainingQty / $remainingDays, 2)
: 0;
//$todayTarget = $remainingDays > 0
// ? $remainingQty / $remainingDays
// : 0;
$producedQty = isset($producedData[$key][$date])
? $producedData[$key][$date]->total_qty
: 0;
$row['daily_target_dynamic'][$date] = $todayTarget;
$row['produced_quantity'][$date] = $producedQty;
// Carry forward pending
$remainingQty -= $producedQty;
if ($remainingQty < 0) {
$remainingQty = 0;
}
$remainingDays--;
}
return $row;
})
->toArray();
}
public function exportProductionData()
{
return Excel::download(
new ProductionPlanExport($this->records, $this->dates),
'production_plan_data.xlsx'
);
}
public function render()
{
// return view('livewire.production-target-plan');
return view('livewire.production-target-plan', [
'records' => $this->records,
'dates' => $this->dates,
]);
}
}

View File

@@ -1,65 +0,0 @@
<?php
namespace App\Livewire;
use App\Models\ProductionQuantity;
use Livewire\Component;
class StickerValidation extends Component
{
public $plantId;
public $refNumber;
public $serialNumber;
public bool $materialInvoice = false;
public $records = [];
protected $listeners = [
'refreshEmptySticker' => 'loadStickerData',
'addStickerToList' => 'loadSticker'
];
public function loadStickerData($plantId, $refNumber)
{
$this->plantId = $plantId;
$this->refNumber = $refNumber;
// $this->records = ProductionQuantity::where('plant_id', $plantId)
// ->where('production_order', $refNumber)
// ->orderBy('created_at', 'asc')
// ->get(['serial_number', 'operator_id']);
$this->records = ProductionQuantity::query()
->where('production_quantities.plant_id', $plantId)
->where('production_quantities.production_order', $refNumber)
->leftJoin(
'sticker_validations',
'sticker_validations.serial_number',
'=',
'production_quantities.serial_number'
)
->orderBy('production_quantities.created_at', 'asc')
->get([
'production_quantities.serial_number',
'production_quantities.operator_id',
'sticker_validations.status',
'sticker_validations.sticker_id',
])
->map(function ($row) {
$row->status = $row->status ?? '';
return $row;
});
//dd($this->records);
}
public function render()
{
return view('livewire.sticker-validation');
}
}

View File

@@ -1,32 +0,0 @@
<?php
namespace App\Livewire;
use Livewire\Component;
class Webcam extends Component
{
public string $capturedPhoto = '';
// Called from JavaScript when a photo is taken
public function setPhoto(string $photo): void
{
$this->capturedPhoto = $photo;
// Fires a browser event that the Filament form will listen to
$this->dispatch('photo-captured', photo: $photo);
}
// Called from JavaScript when user clicks "Retake"
public function clearPhoto(): void
{
$this->capturedPhoto = '';
$this->dispatch('photo-captured', photo: '');
}
public function render()
{
return view('livewire.webcam');
}
}

View File

@@ -1,32 +0,0 @@
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsTo;
use Illuminate\Database\Eloquent\SoftDeletes;
class EmployeeMaster extends Model
{
use SoftDeletes;
protected $fillable = [
'plant_id',
'name',
'code',
'department',
'designation',
'email',
'mobile_number',
'created_at',
'updated_at',
'created_by',
'updated_by',
];
public function plant(): BelongsTo
{
return $this->belongsTo(Plant::class);
}
}

View File

@@ -3,22 +3,20 @@
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsTo;
use Illuminate\Database\Eloquent\SoftDeletes;
use Illuminate\Database\Eloquent\Relations\BelongsTo;
class Item extends Model
{
use SoftDeletes;
protected $fillable = [
'plant_id',
'line_id',
"plant_id",
'category',
'code',
'description',
'hourly_quantity',
'uom',
'line_capacity',
];
public function plant(): BelongsTo
@@ -26,11 +24,6 @@ class Item extends Model
return $this->belongsTo(Plant::class);
}
public function line(): BelongsTo
{
return $this->belongsTo(Line::class);
}
public function stickerMasters()
{
return $this->hasMany(StickerMaster::class, 'item_id', 'id');
@@ -50,9 +43,4 @@ class Item extends Model
{
return $this->hasMany(TestingPanelReading::class);
}
public function itemCharacteristics()
{
return $this->hasMany(ItemCharacteristic::class, 'item_id', 'id');
}
}

View File

@@ -1,166 +0,0 @@
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsTo;
use Illuminate\Database\Eloquent\SoftDeletes;
class ItemCharacteristic extends Model
{
use SoftDeletes;
protected $fillable = [
'plant_id',
'item_id',
'class',
'zz1_cn_bill_ord',
'zmm_amps',
'zmm_brand',
'zmm_degreeofprotection',
'zmm_delivery',
'zmm_dir_rot',
'zmm_discharge',
'zmm_discharge_max',
'zmm_discharge_min',
'zmm_duty',
'zmm_eff_motor',
'zmm_eff_pump',
'zmm_frequency',
'zmm_head',
'zmm_heading',
'zmm_head_max',
'zmm_head_minimum',
'zmm_idx_eff_mtr',
'zmm_idx_eff_pump',
'zmm_kvacode',
'zmm_maxambtemp',
'zmm_mincoolingflow',
'zmm_motorseries',
'zmm_motor_model',
'zmm_outlet',
'zmm_phase',
'zmm_pressure',
'zmm_pumpflowtype',
'zmm_pumpseries',
'zmm_pump_model',
'zmm_ratedpower',
'zmm_region',
'zmm_servicefactor',
'zmm_servicefactormaximumamps',
'zmm_speed',
'zmm_suction',
'zmm_suctionxdelivery',
'zmm_supplysource',
'zmm_temperature',
'zmm_thrustload',
'zmm_volts',
'zmm_wire',
'zmm_package',
'zmm_pvarrayrating',
'zmm_isi',
'zmm_isimotor',
'zmm_isipump',
'zmm_isipumpset',
'zmm_pumpset_model',
'zmm_stages',
'zmm_headrange',
'zmm_overall_efficiency',
'zmm_connection',
'zmm_min_bore_size',
'zmm_isireference',
'zmm_category',
'zmm_submergence',
'zmm_capacitorstart',
'zmm_capacitorrun',
'zmm_inch',
'zmm_motor_type',
'zmm_dismantle_direction',
'zmm_eff_ovrall',
'zmm_bodymoc',
'zmm_rotormoc',
'zmm_dlwl',
'zmm_inputpower',
'zmm_imp_od',
'zmm_ambtemp',
'zmm_de',
'zmm_dischargerange',
'zmm_efficiency_class',
'zmm_framesize',
'zmm_impellerdiameter',
'zmm_insulationclass',
'zmm_maxflow',
'zmm_minhead',
'zmm_mtrlofconst',
'zmm_nde',
'zmm_powerfactor',
'zmm_tagno',
'zmm_year',
'zmm_laser_name',
'zmm_beenote',
'zmm_beenumber',
'zmm_beestar',
'zmm_logo_ce',
'zmm_codeclass',
'zmm_colour',
'zmm_logo_cp',
'zmm_grade',
'zmm_grwt_pset',
'zmm_grwt_cable',
'zmm_grwt_motor',
'zmm_grwt_pf',
'zmm_grwt_pump',
'zmm_isivalve',
'zmm_isi_wc',
'zmm_labelperiod',
'zmm_length',
'zmm_license_cml_no',
'zmm_mfgmonyr',
'zmm_modelyear',
'zmm_motoridentification',
'zmm_newt_pset',
'zmm_newt_cable',
'zmm_newt_motor',
'zmm_newt_pf',
'zmm_newt_pump',
'zmm_logo_nsf',
'zmm_packtype',
'zmm_panel',
'zmm_performance_factor',
'zmm_pumpidentification',
'zmm_psettype',
'zmm_size',
'zmm_eff_ttl',
'zmm_type',
'zmm_usp',
'zmm_1',
'zmm_2',
'zmm_3',
'zmm_4',
'zmm_5',
'zmm_6',
'zmm_7',
'zmm_8',
'zmm_9',
'zmm_10',
'zmm_11',
'zmm_12',
'zmm_13',
'zmm_14',
'zmm_15',
'created_at',
'updated_at',
'created_by',
'updated_by',
];
public function plant(): BelongsTo
{
return $this->belongsTo(Plant::class);
}
public function item(): BelongsTo
{
return $this->belongsTo(Item::class);
}
}

View File

@@ -13,7 +13,6 @@ class Line extends Model
protected $fillable = [
"plant_id",
"block_id",
"name",
"type",
"group_work_center",
@@ -35,11 +34,6 @@ class Line extends Model
return $this->belongsTo(Plant::class);
}
public function block(): BelongsTo
{
return $this->belongsTo(Block::class);
}
public function testingPanelReadings()
{
return $this->hasMany(TestingPanelReading::class);

View File

@@ -102,9 +102,4 @@ class Plant extends Model
{
return $this->hasMany(User::class, 'plant_id', 'id');
}
public function itemCharacteristics()
{
return $this->hasMany(ItemCharacteristic::class, 'plant_id', 'id');
}
}

View File

@@ -12,15 +12,12 @@ class ProductionPlan extends Model
protected $fillable = [
"plant_id",
"item_id",
"shift_id",
"created_at",
"line_id",
"plan_quantity",
"production_quantity",
"operator_id",
"working_days",
"leave_dates",
];
public function plant(): BelongsTo
@@ -37,9 +34,4 @@ class ProductionPlan extends Model
{
return $this->belongsTo(Line::class);
}
public function item(): BelongsTo
{
return $this->belongsTo(Item::class);
}
}

View File

@@ -16,7 +16,6 @@ class ProductionQuantity extends Model
protected $fillable = [
"plant_id",
"machine_id",
"shift_id",
"line_id",
"item_id",
@@ -51,11 +50,6 @@ class ProductionQuantity extends Model
return $this->belongsTo(Item::class);
}
public function machine(): BelongsTo
{
return $this->belongsTo(Machine::class);
}
protected static function booted()
{
static::created(function ($productionQuantity) {

View File

@@ -1,46 +0,0 @@
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsTo;
use Illuminate\Database\Eloquent\SoftDeletes;
class RequestQuotation extends Model
{
use SoftDeletes;
protected $fillable = [
'rfq_number',
'rfq_date_time',
'pickup_address',
'delivery_address',
'weight',
'volumetrice_size_inch',
'type_of_vehicle',
'special_type',
'no_of_vehicle',
'product_name',
'loading_by',
'unloading_by',
'pick_and_delivery',
'payment_term',
'paid_topay',
'require_date_time',
'transporter_name',
'total_freight_charge',
'transit_day',
'spot_rate_transport_master_id',
'created_at',
'updated_at',
'created_by',
'updated_by',
];
public function spotRateTransportMaster(): BelongsTo
{
return $this->belongsTo(SpotRateTransportMaster::class);
}
}

View File

@@ -1,30 +0,0 @@
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsTo;
use Illuminate\Database\Eloquent\SoftDeletes;
use phpseclib3\Crypt\Common\Formats\Signature\Raw;
class RfqTransporterBid extends Model
{
use SoftDeletes;
protected $fillable = [
'request_quotation_id',
'transporter_name',
'total_freight_charge',
'transit_day',
'created_at',
'updated_at',
'created_by',
'updated_by',
];
public function requestQuotation(): BelongsTo
{
return $this->belongsTo(RequestQuotation::class);
// return $this->belongsTo(RequestQuotation::class, 'request_quotation_id');
}
}

View File

@@ -1,25 +0,0 @@
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsTo;
use Illuminate\Database\Eloquent\SoftDeletes;
class SpotRateTransportMaster extends Model
{
use SoftDeletes;
protected $casts = [
'user_name' => 'array',
];
protected $fillable = [
'group_name',
'user_name',
'created_at',
'updated_at',
'created_by',
'updated_by',
];
}

View File

@@ -15,7 +15,6 @@ class StickerDetail extends Model
'design_element_type',
'element_id',
'element_type',
'characteristics_type',
'string_value',
'string_font',
'string_size',
@@ -25,13 +24,12 @@ class StickerDetail extends Model
'string_y_value',
'shape_name',
'shape_pen_size',
'curve_radius',
'shape_x1_value',
'shape_y1_value',
'shape_x2_value',
'shape_y2_value',
// 'image_path',
// 'image_type',
'image_path',
'image_type',
'image_x',
'image_y',
'image_width',

View File

@@ -8,136 +8,28 @@ use Illuminate\Database\Eloquent\SoftDeletes;
class StickerMappingMaster extends Model
{
use SoftDeletes;
use SoftDeletes;
protected $fillable = [
'plant_id',
'item_characteristic_id',
'sticker_structure1_id',
'sticker1_machine_id',
'sticker1_print_ip',
'sticker_structure2_id',
'sticker2_machine_id',
'sticker2_print_ip',
'sticker_structure3_id',
'sticker3_machine_id',
'sticker3_print_ip',
'sticker_structure4_id',
'sticker4_machine_id',
'sticker4_print_ip',
'sticker_structure5_id',
'sticker5_machine_id',
'sticker5_print_ip',
'sticker_structure7_id',
'sticker6_machine_id',
'sticker6_print_ip',
'sticker_structure7_id',
'sticker7_machine_id',
'sticker7_print_ip',
'sticker_structure8_id',
'sticker8_machine_id',
'sticker8_print_ip',
'item_id',
'sticker1',
'sticker2',
'sticker3',
'sticker4',
'sticker5',
'created_at',
'updated_at',
'created_by',
'updated_by',
'updated_by'
];
public function plant()
public function plant(): BelongsTo
{
return $this->belongsTo(Plant::class);
}
public function itemCharacteristic()
{
return $this->belongsTo(ItemCharacteristic::class);
}
public function item(): BelongsTo
{
return $this->belongsTo(Item::class, 'item_id');
}
public function sticker1Structure()
{
return $this->belongsTo(StickerStructureDetail::class, 'sticker_structure1_id');
}
public function sticker2Structure()
{
return $this->belongsTo(StickerStructureDetail::class, 'sticker_structure2_id');
}
public function sticker3Structure()
{
return $this->belongsTo(StickerStructureDetail::class, 'sticker_structure3_id');
}
public function sticker4Structure()
{
return $this->belongsTo(StickerStructureDetail::class, 'sticker_structure4_id');
}
public function sticker5Structure()
{
return $this->belongsTo(StickerStructureDetail::class, 'sticker_structure5_id');
}
public function sticker6Structure()
{
return $this->belongsTo(StickerStructureDetail::class, 'sticker_structure6_id');
}
public function sticker7Structure()
{
return $this->belongsTo(StickerStructureDetail::class, 'sticker_structure7_id');
}
public function sticker8Structure()
{
return $this->belongsTo(StickerStructureDetail::class, 'sticker_structure8_id');
}
// Machine relationships (per sticker)
public function sticker1Machine()
{
return $this->belongsTo(Machine::class, 'sticker1_machine_id');
}
public function sticker2Machine()
{
return $this->belongsTo(Machine::class, 'sticker2_machine_id');
}
public function sticker3Machine()
{
return $this->belongsTo(Machine::class, 'sticker3_machine_id');
}
public function sticker4Machine()
{
return $this->belongsTo(Machine::class, 'sticker4_machine_id');
}
public function sticker5Machine()
{
return $this->belongsTo(Machine::class, 'sticker5_machine_id');
}
public function sticker6Machine()
{
return $this->belongsTo(Machine::class, 'sticker6_machine_id');
}
public function sticker7Machine()
{
return $this->belongsTo(Machine::class, 'sticker7_machine_id');
}
public function sticker8Machine()
{
return $this->belongsTo(Machine::class, 'sticker8_machine_id');
return $this->belongsTo(Item::class);
}
}

View File

@@ -3,7 +3,6 @@
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsTo;
use Illuminate\Database\Eloquent\SoftDeletes;
class StickerStructureDetail extends Model
@@ -12,8 +11,6 @@ class StickerStructureDetail extends Model
use SoftDeletes;
protected $fillable = [
'plant_id',
'item_characteristic_id',
'sticker_id',
'sticker_width',
'sticker_height',
@@ -26,15 +23,4 @@ class StickerStructureDetail extends Model
'created_by',
'updated_by'
];
public function plant(): BelongsTo
{
return $this->belongsTo(Plant::class);
}
public function itemCharacteristic(): BelongsTo
{
return $this->belongsTo(ItemCharacteristic::class, 'item_characteristic_id');
}
}

View File

@@ -1,33 +0,0 @@
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\SoftDeletes;
class StickerValidation extends Model
{
use SoftDeletes;
protected $fillable = [
'plant_id',
'machine_id',
'sticker_id',
'production_order',
'serial_number',
'status',
'created_by',
'updated_by',
'deleted_at',
];
public function plant()
{
return $this->belongsTo(Plant::class);
}
public function machine()
{
return $this->belongsTo(Machine::class);
}
}

View File

@@ -13,13 +13,11 @@ use Illuminate\Foundation\Auth\User as Authenticatable;
use Illuminate\Notifications\Notifiable;
use Spatie\Permission\Traits\HasRoles;
use Illuminate\Database\Eloquent\Relations\BelongsTo;
use NotificationChannels\WebPush\HasPushSubscriptions;
use NotificationChannels\WebPush\PushSubscription;
class User extends Authenticatable implements FilamentUser
{
/** @use HasFactory<\Database\Factories\UserFactory> */
use HasFactory, HasRoles, Notifiable, SoftDeletes, HasSuperAdmin, HasPushSubscriptions;
use HasFactory, HasRoles, Notifiable, SoftDeletes, HasSuperAdmin;
/**
* The attributes that are mass assignable.
@@ -65,9 +63,4 @@ class User extends Authenticatable implements FilamentUser
{
return $this->belongsTo(Plant::class);
}
public function pushSubscriptions()
{
return $this->morphMany(PushSubscription::class, 'subscribable');
}
}

View File

@@ -1,30 +0,0 @@
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsTo;
use Illuminate\Database\Eloquent\SoftDeletes;
class VisitorEntry extends Model
{
use SoftDeletes;
protected $fillable = [
'mobile_number',
'name',
'company',
'purpose_of_visit',
'type',
'in_time',
'out_time',
'photo',
'employee_master_id',
'number_of_person'
];
public function employeeMaster(): BelongsTo
{
return $this->belongsTo(EmployeeMaster::class);
}
}

View File

@@ -1,19 +0,0 @@
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
class WebPushSubscription extends Model
{
protected $table = 'push_subscriptions';
protected $fillable = [
'subscribable_type',
'subscribable_id',
'endpoint',
'public_key',
'auth_token',
'content_encoding',
];
}

View File

@@ -1,108 +0,0 @@
<?php
namespace App\Notifications;
use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Notifications\Messages\MailMessage;
use Illuminate\Notifications\Notification;
use NotificationChannels\WebPush\WebPushMessage;
use NotificationChannels\WebPush\WebPushChannel;
class PushAlertNotification extends Notification
{
use Queueable;
/**
* Create a new notification instance.
*/
// public function __construct()
// {
// //
// }
public $title;
public $body;
public function __construct($title, $body)
{
$this->title = $title;
$this->body = $body;
}
// public function via($notifiable)
// {
// return [WebPushChannel::class];
// }
public function via($notifiable)
{
return [
'database', // ✅ Filament toast
WebPushChannel::class // ✅ Browser / PWA push
];
}
public function toDatabase($notifiable): array
{
return [
'title' => $this->title,
'body' => $this->body,
];
}
// public function toWebPush($notifiable, $notification)
// {
// return (new WebPushMessage)
// ->title('New Alert 🚨')
// ->icon('/pwa-192x192.png')
// ->body('You have a new notification')
// ->action('Open App', 'open_app')
// ->data(['url' => '/admin']);
// }
public function toWebPush($notifiable, $notification)
{
return (new WebPushMessage)
->title($this->title)
->icon('/pwa-192x192.png')
->body($this->body)
->action('Open App', 'open_app')
->data(['url' => '/admin']);
}
/**
* Get the notification's delivery channels.
*
* @return array<int, string>
*/
// public function via(object $notifiable): array
// {
// return ['mail'];
// }
/**
* Get the mail representation of the notification.
*/
// public function toMail(object $notifiable): MailMessage
// {
// return (new MailMessage)
// ->line('The introduction to the notification.')
// ->action('Notification Action', url('/'))
// ->line('Thank you for using our application!');
// }
/**
* Get the array representation of the notification.
*
* @return array<string, mixed>
*/
public function toArray(object $notifiable): array
{
return [
//
];
}
}

View File

@@ -1,106 +0,0 @@
<?php
namespace App\Policies;
use Illuminate\Auth\Access\Response;
use App\Models\ItemCharacteristic;
use App\Models\User;
class ItemCharacteristicPolicy
{
/**
* Determine whether the user can view any models.
*/
public function viewAny(User $user): bool
{
return $user->checkPermissionTo('view-any ItemCharacteristic');
}
/**
* Determine whether the user can view the model.
*/
public function view(User $user, ItemCharacteristic $itemcharacteristic): bool
{
return $user->checkPermissionTo('view ItemCharacteristic');
}
/**
* Determine whether the user can create models.
*/
public function create(User $user): bool
{
return $user->checkPermissionTo('create ItemCharacteristic');
}
/**
* Determine whether the user can update the model.
*/
public function update(User $user, ItemCharacteristic $itemcharacteristic): bool
{
return $user->checkPermissionTo('update ItemCharacteristic');
}
/**
* Determine whether the user can delete the model.
*/
public function delete(User $user, ItemCharacteristic $itemcharacteristic): bool
{
return $user->checkPermissionTo('delete ItemCharacteristic');
}
/**
* Determine whether the user can delete any models.
*/
public function deleteAny(User $user): bool
{
return $user->checkPermissionTo('delete-any ItemCharacteristic');
}
/**
* Determine whether the user can restore the model.
*/
public function restore(User $user, ItemCharacteristic $itemcharacteristic): bool
{
return $user->checkPermissionTo('restore ItemCharacteristic');
}
/**
* Determine whether the user can restore any models.
*/
public function restoreAny(User $user): bool
{
return $user->checkPermissionTo('restore-any ItemCharacteristic');
}
/**
* Determine whether the user can replicate the model.
*/
public function replicate(User $user, ItemCharacteristic $itemcharacteristic): bool
{
return $user->checkPermissionTo('replicate ItemCharacteristic');
}
/**
* Determine whether the user can reorder the models.
*/
public function reorder(User $user): bool
{
return $user->checkPermissionTo('reorder ItemCharacteristic');
}
/**
* Determine whether the user can permanently delete the model.
*/
public function forceDelete(User $user, ItemCharacteristic $itemcharacteristic): bool
{
return $user->checkPermissionTo('force-delete ItemCharacteristic');
}
/**
* Determine whether the user can permanently delete any models.
*/
public function forceDeleteAny(User $user): bool
{
return $user->checkPermissionTo('force-delete-any ItemCharacteristic');
}
}

View File

@@ -1,106 +0,0 @@
<?php
namespace App\Policies;
use Illuminate\Auth\Access\Response;
use App\Models\RequestQuotation;
use App\Models\User;
class RequestQuotationPolicy
{
/**
* Determine whether the user can view any models.
*/
public function viewAny(User $user): bool
{
return $user->checkPermissionTo('view-any RequestQuotation');
}
/**
* Determine whether the user can view the model.
*/
public function view(User $user, RequestQuotation $requestquotation): bool
{
return $user->checkPermissionTo('view RequestQuotation');
}
/**
* Determine whether the user can create models.
*/
public function create(User $user): bool
{
return $user->checkPermissionTo('create RequestQuotation');
}
/**
* Determine whether the user can update the model.
*/
public function update(User $user, RequestQuotation $requestquotation): bool
{
return $user->checkPermissionTo('update RequestQuotation');
}
/**
* Determine whether the user can delete the model.
*/
public function delete(User $user, RequestQuotation $requestquotation): bool
{
return $user->checkPermissionTo('delete RequestQuotation');
}
/**
* Determine whether the user can delete any models.
*/
public function deleteAny(User $user): bool
{
return $user->checkPermissionTo('delete-any RequestQuotation');
}
/**
* Determine whether the user can restore the model.
*/
public function restore(User $user, RequestQuotation $requestquotation): bool
{
return $user->checkPermissionTo('restore RequestQuotation');
}
/**
* Determine whether the user can restore any models.
*/
public function restoreAny(User $user): bool
{
return $user->checkPermissionTo('restore-any RequestQuotation');
}
/**
* Determine whether the user can replicate the model.
*/
public function replicate(User $user, RequestQuotation $requestquotation): bool
{
return $user->checkPermissionTo('replicate RequestQuotation');
}
/**
* Determine whether the user can reorder the models.
*/
public function reorder(User $user): bool
{
return $user->checkPermissionTo('reorder RequestQuotation');
}
/**
* Determine whether the user can permanently delete the model.
*/
public function forceDelete(User $user, RequestQuotation $requestquotation): bool
{
return $user->checkPermissionTo('force-delete RequestQuotation');
}
/**
* Determine whether the user can permanently delete any models.
*/
public function forceDeleteAny(User $user): bool
{
return $user->checkPermissionTo('force-delete-any RequestQuotation');
}
}

View File

@@ -1,106 +0,0 @@
<?php
namespace App\Policies;
use Illuminate\Auth\Access\Response;
use App\Models\RfqTransporterBid;
use App\Models\User;
class RfqTransporterBidPolicy
{
/**
* Determine whether the user can view any models.
*/
public function viewAny(User $user): bool
{
return $user->checkPermissionTo('view-any RfqTransporterBid');
}
/**
* Determine whether the user can view the model.
*/
public function view(User $user, RfqTransporterBid $rfqtransporterbid): bool
{
return $user->checkPermissionTo('view RfqTransporterBid');
}
/**
* Determine whether the user can create models.
*/
public function create(User $user): bool
{
return $user->checkPermissionTo('create RfqTransporterBid');
}
/**
* Determine whether the user can update the model.
*/
public function update(User $user, RfqTransporterBid $rfqtransporterbid): bool
{
return $user->checkPermissionTo('update RfqTransporterBid');
}
/**
* Determine whether the user can delete the model.
*/
public function delete(User $user, RfqTransporterBid $rfqtransporterbid): bool
{
return $user->checkPermissionTo('delete RfqTransporterBid');
}
/**
* Determine whether the user can delete any models.
*/
public function deleteAny(User $user): bool
{
return $user->checkPermissionTo('delete-any RfqTransporterBid');
}
/**
* Determine whether the user can restore the model.
*/
public function restore(User $user, RfqTransporterBid $rfqtransporterbid): bool
{
return $user->checkPermissionTo('restore RfqTransporterBid');
}
/**
* Determine whether the user can restore any models.
*/
public function restoreAny(User $user): bool
{
return $user->checkPermissionTo('restore-any RfqTransporterBid');
}
/**
* Determine whether the user can replicate the model.
*/
public function replicate(User $user, RfqTransporterBid $rfqtransporterbid): bool
{
return $user->checkPermissionTo('replicate RfqTransporterBid');
}
/**
* Determine whether the user can reorder the models.
*/
public function reorder(User $user): bool
{
return $user->checkPermissionTo('reorder RfqTransporterBid');
}
/**
* Determine whether the user can permanently delete the model.
*/
public function forceDelete(User $user, RfqTransporterBid $rfqtransporterbid): bool
{
return $user->checkPermissionTo('force-delete RfqTransporterBid');
}
/**
* Determine whether the user can permanently delete any models.
*/
public function forceDeleteAny(User $user): bool
{
return $user->checkPermissionTo('force-delete-any RfqTransporterBid');
}
}

View File

@@ -1,106 +0,0 @@
<?php
namespace App\Policies;
use Illuminate\Auth\Access\Response;
use App\Models\SpotRateTransportMaster;
use App\Models\User;
class SpotRateTransportMasterPolicy
{
/**
* Determine whether the user can view any models.
*/
public function viewAny(User $user): bool
{
return $user->checkPermissionTo('view-any SpotRateTransportMaster');
}
/**
* Determine whether the user can view the model.
*/
public function view(User $user, SpotRateTransportMaster $spotratetransportmaster): bool
{
return $user->checkPermissionTo('view SpotRateTransportMaster');
}
/**
* Determine whether the user can create models.
*/
public function create(User $user): bool
{
return $user->checkPermissionTo('create SpotRateTransportMaster');
}
/**
* Determine whether the user can update the model.
*/
public function update(User $user, SpotRateTransportMaster $spotratetransportmaster): bool
{
return $user->checkPermissionTo('update SpotRateTransportMaster');
}
/**
* Determine whether the user can delete the model.
*/
public function delete(User $user, SpotRateTransportMaster $spotratetransportmaster): bool
{
return $user->checkPermissionTo('delete SpotRateTransportMaster');
}
/**
* Determine whether the user can delete any models.
*/
public function deleteAny(User $user): bool
{
return $user->checkPermissionTo('delete-any SpotRateTransportMaster');
}
/**
* Determine whether the user can restore the model.
*/
public function restore(User $user, SpotRateTransportMaster $spotratetransportmaster): bool
{
return $user->checkPermissionTo('restore SpotRateTransportMaster');
}
/**
* Determine whether the user can restore any models.
*/
public function restoreAny(User $user): bool
{
return $user->checkPermissionTo('restore-any SpotRateTransportMaster');
}
/**
* Determine whether the user can replicate the model.
*/
public function replicate(User $user, SpotRateTransportMaster $spotratetransportmaster): bool
{
return $user->checkPermissionTo('replicate SpotRateTransportMaster');
}
/**
* Determine whether the user can reorder the models.
*/
public function reorder(User $user): bool
{
return $user->checkPermissionTo('reorder SpotRateTransportMaster');
}
/**
* Determine whether the user can permanently delete the model.
*/
public function forceDelete(User $user, SpotRateTransportMaster $spotratetransportmaster): bool
{
return $user->checkPermissionTo('force-delete SpotRateTransportMaster');
}
/**
* Determine whether the user can permanently delete any models.
*/
public function forceDeleteAny(User $user): bool
{
return $user->checkPermissionTo('force-delete-any SpotRateTransportMaster');
}
}

View File

@@ -1,106 +0,0 @@
<?php
namespace App\Policies;
use Illuminate\Auth\Access\Response;
use App\Models\StickerDetail;
use App\Models\User;
class StickerDetailPolicy
{
/**
* Determine whether the user can view any models.
*/
public function viewAny(User $user): bool
{
return $user->checkPermissionTo('view-any StickerDetail');
}
/**
* Determine whether the user can view the model.
*/
public function view(User $user, StickerDetail $stickerdetail): bool
{
return $user->checkPermissionTo('view StickerDetail');
}
/**
* Determine whether the user can create models.
*/
public function create(User $user): bool
{
return $user->checkPermissionTo('create StickerDetail');
}
/**
* Determine whether the user can update the model.
*/
public function update(User $user, StickerDetail $stickerdetail): bool
{
return $user->checkPermissionTo('update StickerDetail');
}
/**
* Determine whether the user can delete the model.
*/
public function delete(User $user, StickerDetail $stickerdetail): bool
{
return $user->checkPermissionTo('delete StickerDetail');
}
/**
* Determine whether the user can delete any models.
*/
public function deleteAny(User $user): bool
{
return $user->checkPermissionTo('delete-any StickerDetail');
}
/**
* Determine whether the user can restore the model.
*/
public function restore(User $user, StickerDetail $stickerdetail): bool
{
return $user->checkPermissionTo('restore StickerDetail');
}
/**
* Determine whether the user can restore any models.
*/
public function restoreAny(User $user): bool
{
return $user->checkPermissionTo('restore-any StickerDetail');
}
/**
* Determine whether the user can replicate the model.
*/
public function replicate(User $user, StickerDetail $stickerdetail): bool
{
return $user->checkPermissionTo('replicate StickerDetail');
}
/**
* Determine whether the user can reorder the models.
*/
public function reorder(User $user): bool
{
return $user->checkPermissionTo('reorder StickerDetail');
}
/**
* Determine whether the user can permanently delete the model.
*/
public function forceDelete(User $user, StickerDetail $stickerdetail): bool
{
return $user->checkPermissionTo('force-delete StickerDetail');
}
/**
* Determine whether the user can permanently delete any models.
*/
public function forceDeleteAny(User $user): bool
{
return $user->checkPermissionTo('force-delete-any StickerDetail');
}
}

View File

@@ -1,106 +0,0 @@
<?php
namespace App\Policies;
use Illuminate\Auth\Access\Response;
use App\Models\StickerValidation;
use App\Models\User;
class StickerValidationPolicy
{
/**
* Determine whether the user can view any models.
*/
public function viewAny(User $user): bool
{
return $user->checkPermissionTo('view-any StickerValidation');
}
/**
* Determine whether the user can view the model.
*/
public function view(User $user, StickerValidation $stickervalidation): bool
{
return $user->checkPermissionTo('view StickerValidation');
}
/**
* Determine whether the user can create models.
*/
public function create(User $user): bool
{
return $user->checkPermissionTo('create StickerValidation');
}
/**
* Determine whether the user can update the model.
*/
public function update(User $user, StickerValidation $stickervalidation): bool
{
return $user->checkPermissionTo('update StickerValidation');
}
/**
* Determine whether the user can delete the model.
*/
public function delete(User $user, StickerValidation $stickervalidation): bool
{
return $user->checkPermissionTo('delete StickerValidation');
}
/**
* Determine whether the user can delete any models.
*/
public function deleteAny(User $user): bool
{
return $user->checkPermissionTo('delete-any StickerValidation');
}
/**
* Determine whether the user can restore the model.
*/
public function restore(User $user, StickerValidation $stickervalidation): bool
{
return $user->checkPermissionTo('restore StickerValidation');
}
/**
* Determine whether the user can restore any models.
*/
public function restoreAny(User $user): bool
{
return $user->checkPermissionTo('restore-any StickerValidation');
}
/**
* Determine whether the user can replicate the model.
*/
public function replicate(User $user, StickerValidation $stickervalidation): bool
{
return $user->checkPermissionTo('replicate StickerValidation');
}
/**
* Determine whether the user can reorder the models.
*/
public function reorder(User $user): bool
{
return $user->checkPermissionTo('reorder StickerValidation');
}
/**
* Determine whether the user can permanently delete the model.
*/
public function forceDelete(User $user, StickerValidation $stickervalidation): bool
{
return $user->checkPermissionTo('force-delete StickerValidation');
}
/**
* Determine whether the user can permanently delete any models.
*/
public function forceDeleteAny(User $user): bool
{
return $user->checkPermissionTo('force-delete-any StickerValidation');
}
}

View File

@@ -4,7 +4,6 @@ namespace App\Providers\Filament;
use Althinect\FilamentSpatieRolesPermissions\FilamentSpatieRolesPermissionsPlugin;
use App\Filament\Pages\InvoiceDashboard;
use App\Filament\Pages\NotificationSettings;
use Filament\Facades\Filament;
use Filament\Http\Middleware\Authenticate;
use Filament\Http\Middleware\AuthenticateSession;
@@ -29,7 +28,6 @@ use App\Filament\Auth\CustomLogin as AuthCustomLogin;
use App\Filament\Pages\CustomLogin;
use Filament\View\PanelsRenderHook;
use Filament\Support\Facades\FilamentView;
use Illuminate\Support\Facades\Blade;
class AdminPanelProvider extends PanelProvider
@@ -61,7 +59,6 @@ class AdminPanelProvider extends PanelProvider
->discoverResources(in: app_path('Filament/Resources'), for: 'App\\Filament\\Resources')
->discoverPages(in: app_path('Filament/Pages'), for: 'App\\Filament\\Pages')
->pages([
])
->discoverWidgets(in: app_path('Filament/Widgets'), for: 'App\\Filament\\Widgets')
// ->widgets([
@@ -126,15 +123,6 @@ class AdminPanelProvider extends PanelProvider
public function boot(): void
{
FilamentView::registerRenderHook('panels::body.end', function () {
if (url()->current() == config('app.url') . '/admin') {
return '<script src="' . asset('js/push.js') . '"></script>';
}
return '';
});
FilamentView::registerRenderHook('panels::head.end', function () {
// Only inject on the "home" page (or specific route)
if (url()->current() == config('app.url') . '/admin') {
@@ -161,10 +149,5 @@ class AdminPanelProvider extends PanelProvider
}
return '';
});
FilamentView::registerRenderHook(
PanelsRenderHook::BODY_END,
fn (): string => Blade::render("@livewire('chat-bot')"),
);
}
}

View File

@@ -1,403 +0,0 @@
<?php
namespace App\Services;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Log;
/**
* ChatbotService (Advanced Mode)
* ─────────────────────────────────────────────────────────────────────────────
* Parses STRUCTURED user inputs via regex no LLM involved.
*
* HOW TO ADD A NEW COMMAND:
* 1. Add an entry to $handlers with a regex pattern and a handler method name.
* 2. Write the private handler method (receives the captured group as $value).
* 3. Add a usage example to unknownCommand() so users know about it.
*
* Pattern convention: /keyword\s*=\s*(.+)/i
* - The first capture group is the raw value after "=".
* - The handler receives it already trimmed.
*/
class ChatbotService
{
/**
* Registry of structured-command handlers.
*
* Each entry:
* 'pattern' PCRE regex; capture group 1 is the extracted value.
* 'handler' name of the private method that processes the command.
*
* For two-value commands (e.g. invoice report), group 1 and group 2 are
* both passed to the handler; single-value handlers simply ignore $value2.
*/
private array $handlers = [
[
'pattern' => '/inv(?:oice)?(?:\s*(?:number|num|no\.?))?\s*(?:=|is| |equal\s+to)\s*([^\s,\.]+)/i',
'handler' => 'handleInvoice',
],
// ── Invoice report: item type lookup ──────────────────────────────────
// Accepts patterns like:
// item = 674071 plant = Vahinie Unit 2
// item code = 674071 plant = Vahinie Unit 2
// check item 674071 for plant Vahinie Unit 2
[
'pattern' => '/item(?:\s*code)?\s*(?:=|is|:)?\s*([^\s,]+)\s+(?:for\s+)?plant\s*(?:=|is|:)?\s*(.+)/i',
'handler' => 'handleInvoiceReport',
],
// ── Add more commands here ────────────────────────────────────────────
// Example:
// [
// 'pattern' => '/^\s*serial\s*=\s*(.+)/i',
// 'handler' => 'handleSerial',
// ],
];
// ─────────────────────────────────────────────────────────────────────────
// Public entry point
// ─────────────────────────────────────────────────────────────────────────
/**
* Dispatch the user's input to the matching handler.
*/
public function ask(string $input): string
{
$input = trim($input);
foreach ($this->handlers as $entry) {
if (preg_match($entry['pattern'], $input, $matches)) {
$value = trim($matches[1] ?? '');
$value2 = trim($matches[2] ?? '');
return $this->{$entry['handler']}($value, $value2);
}
}
return $this->unknownCommand($input);
}
// ─────────────────────────────────────────────────────────────────────────
// Handler: invoice = <invoice_number>
// ─────────────────────────────────────────────────────────────────────────
/**
* Looks up scan status for an invoice number in invoice_validations.
* Returns a plain-English string (used by the Advanced / free-text path).
* Structured callers should use getInvoiceData() directly.
*/
private function handleInvoice(string $invoiceNumber, string $_unused = ''): string
{
$data = $this->getInvoiceData($invoiceNumber);
// For the plain-text path (advanced mode / ChatbotService::ask()),
// reassemble a human-readable sentence from the structured data.
if (in_array($data['type'], ['invalid', 'error', 'not_found'], true)) {
return $data['message'];
}
if ($data['type'] === 'all_scanned') {
$n = $data['total'];
$itemWord = $n === 1 ? 'serial number' : 'serial numbers';
return "For invoice number {$data['invoice_number']}, all {$n} {$itemWord} "
. ($n === 1 ? 'has' : 'have') . ' been scanned. ✅';
}
// partial or none_scanned
$total = $data['total'];
$scanned = $data['scanned'];
$notScan = $data['not_scanned'];
$inv = $data['invoice_number'];
$itemWord = $total === 1 ? 'serial number' : 'serial numbers';
if ($scanned === 0) {
$msg = "For invoice number {$inv}, there "
. ($total === 1 ? 'is' : 'are') . " {$total} {$itemWord} "
. 'and none have been scanned.';
} else {
$msg = "For invoice number {$inv}, there "
. ($total === 1 ? 'is' : 'are') . " {$total} {$itemWord} in total. "
. "Out of which {$scanned} "
. ($scanned === 1 ? 'has' : 'have') . ' been scanned and '
. "{$notScan} "
. ($notScan === 1 ? 'has' : 'have') . ' not been scanned.';
}
if (! empty($data['unscanned_serials'])) {
$msg .= ' Unscanned serial numbers are: '
. implode(', ', $data['unscanned_serials']) . '.';
}
return $msg;
}
// ─────────────────────────────────────────────────────────────────────────
// Public structured accessor — used by ChatBot (Basic mode)
// ─────────────────────────────────────────────────────────────────────────
/**
* Returns structured scan-status data for an invoice number.
*
* Return shape:
* [
* 'type' => 'all_scanned' | 'partial' | 'none_scanned'
* | 'not_found' | 'error' | 'invalid',
* 'message' => string, // one-line human summary (no serial list)
* 'invoice_number' => string,
* 'total' => int,
* 'scanned' => int,
* 'not_scanned' => int,
* 'unscanned_serials' => string[], // full list — may be large
* ]
*/
public function getInvoiceData(string $invoiceNumber): array
{
$invoiceNumber = preg_replace('/\s+/', '', $invoiceNumber);
if (empty($invoiceNumber)) {
return [
'type' => 'invalid',
'message' => 'Please provide a valid invoice number. Example: invoice = 3RA0013333',
'invoice_number' => '',
'total' => 0,
'scanned' => 0,
'not_scanned' => 0,
'unscanned_serials' => [],
];
}
try {
$rows = DB::select("
SELECT
COALESCE(scanned_status, 'not scanned') AS status,
COUNT(*) AS total_count,
STRING_AGG(
CASE
WHEN scanned_status IS NULL THEN serial_number::text
END,
', '
) AS serial_numbers_not_scanned
FROM invoice_validations
WHERE invoice_number = ?
GROUP BY scanned_status
", [$invoiceNumber]);
} catch (\Exception $e) {
Log::error('ChatbotService: invoice query failed', [
'invoice' => $invoiceNumber,
'error' => $e->getMessage(),
]);
return [
'type' => 'error',
'message' => "Sorry, I couldn't fetch data for invoice {$invoiceNumber}. "
. 'Please try again or contact support if this keeps happening.',
'invoice_number' => $invoiceNumber,
'total' => 0,
'scanned' => 0,
'not_scanned' => 0,
'unscanned_serials' => [],
];
}
if (empty($rows)) {
return [
'type' => 'not_found',
'message' => "No records found for invoice number {$invoiceNumber}. "
. 'Please double-check the invoice number and try again.',
'invoice_number' => $invoiceNumber,
'total' => 0,
'scanned' => 0,
'not_scanned' => 0,
'unscanned_serials' => [],
];
}
// ── Aggregate rows ────────────────────────────────────────────────────
$totalScanned = 0;
$totalNotScanned = 0;
$unscannedSerials = [];
foreach ($rows as $row) {
if ($row->status === 'not scanned') {
$totalNotScanned = (int) $row->total_count;
if (! empty($row->serial_numbers_not_scanned)) {
$unscannedSerials = array_values(
array_filter(
array_map('trim', explode(',', $row->serial_numbers_not_scanned))
)
);
}
} else {
$totalScanned += (int) $row->total_count;
}
}
$grandTotal = $totalScanned + $totalNotScanned;
// ── All scanned ───────────────────────────────────────────────────────
if ($totalNotScanned === 0) {
$n = $grandTotal;
$itemWord = $n === 1 ? 'serial number' : 'serial numbers';
return [
'type' => 'all_scanned',
'message' => "All {$n} {$itemWord} scanned for invoice {$invoiceNumber}. ✅",
'invoice_number' => $invoiceNumber,
'total' => $grandTotal,
'scanned' => $totalScanned,
'not_scanned' => 0,
'unscanned_serials' => [],
];
}
// ── None / partial scanned ────────────────────────────────────────────
$type = $totalScanned === 0 ? 'none_scanned' : 'partial';
$itemWord = $grandTotal === 1 ? 'serial number' : 'serial numbers';
if ($totalScanned === 0) {
$summary = "Invoice {$invoiceNumber}{$grandTotal} {$itemWord}, none scanned yet.";
} else {
$summary = "Invoice {$invoiceNumber}{$grandTotal} {$itemWord} total: "
. "{$totalScanned} scanned, {$totalNotScanned} not scanned.";
}
return [
'type' => $type,
'message' => $summary,
'invoice_number' => $invoiceNumber,
'total' => $grandTotal,
'scanned' => $totalScanned,
'not_scanned' => $totalNotScanned,
'unscanned_serials' => $unscannedSerials,
];
}
// ─────────────────────────────────────────────────────────────────────────
// Handler: item = <item_code> plant = <plant_name>
// ─────────────────────────────────────────────────────────────────────────
/**
* Determines whether an item is a serial invoice or material invoice
* for a given plant, using the sticker_masters table.
*
* @param string $itemCode Extracted item code (capture group 1)
* @param string $plantName Extracted plant name (capture group 2)
*/
private function handleInvoiceReport(string $itemCode, string $plantName): string
{
$itemCode = trim($itemCode);
$plantName = trim($plantName);
if (empty($itemCode)) {
return 'Please provide an item code. Example: item = 674071 plant = Vahinie Unit 2';
}
if (empty($plantName)) {
return 'Please provide a plant name. Example: item = 674071 plant = Vahinie Unit 2';
}
try {
$rows = DB::select("
WITH plant_item AS (
SELECT ? AS user_plant,
? AS user_item_code
),
t1 AS (
SELECT
plants.id AS plant_id,
plants.name AS plant_name,
ARRAY_AGG(items.code) AS item_codes
FROM plants
LEFT JOIN items ON plants.id = items.plant_id
GROUP BY plants.id, plants.name
),
t2 AS (
SELECT
t1.plant_id,
t1.plant_name,
CASE
WHEN plant_item.user_item_code = ANY(t1.item_codes) THEN 1
ELSE 0
END AS exists_flag
FROM t1
CROSS JOIN plant_item
WHERE t1.plant_name = plant_item.user_plant
),
t3 AS (
SELECT t2.plant_id, t2.plant_name, t2.exists_flag,
plant_item.user_item_code
FROM t2
LEFT JOIN plant_item ON plant_item.user_plant = t2.plant_name
),
t4 AS (
SELECT items.id AS item_id,
t3.plant_id, t3.plant_name, t3.exists_flag, t3.user_item_code
FROM t3
LEFT JOIN items
ON t3.plant_id = items.plant_id
AND t3.user_item_code = items.code
)
SELECT
t4.item_id,
t4.plant_id,
t4.plant_name,
t4.exists_flag,
t4.user_item_code,
COALESCE(sticker_masters.material_type, 0) AS material_type,
CASE
WHEN sticker_masters.item_id IS NULL
THEN 'no match found'
WHEN COALESCE(sticker_masters.material_type, 0) = 0
THEN 'serial invoice'
ELSE 'material invoice'
END AS invoice_description
FROM t4
LEFT JOIN sticker_masters
ON sticker_masters.plant_id = t4.plant_id
AND sticker_masters.item_id = t4.item_id
", [$plantName, $itemCode]);
} catch (\Exception $e) {
Log::error('ChatbotService: invoice report query failed', [
'plant' => $plantName,
'item_code' => $itemCode,
'error' => $e->getMessage(),
]);
return "Sorry, I couldn't fetch data for item {$itemCode} in plant {$plantName}. "
. 'Please try again or contact support.';
}
if (empty($rows)) {
return "No data found for plant \"{$plantName}\". Please check the plant name and try again.";
}
$row = $rows[0];
if ((int) $row->exists_flag === 0) {
return 'Provided item code does not exist in the item table.';
}
return match ($row->invoice_description) {
'no match found' => "Item not found in sticker master for the plant {$row->plant_name}.",
'serial invoice' => 'It is a serial invoice item.',
'material invoice' => 'It is a material invoice item.',
default => 'Unexpected result. Please contact support.',
};
}
// ─────────────────────────────────────────────────────────────────────────
// Fallback for unrecognised input
// ─────────────────────────────────────────────────────────────────────────
private function unknownCommand(string $input): string
{
return "I didn't recognise that command. Please include a supported keyword with a value after '='.\n\n"
. "• Invoice scan status:\n"
. " invoice = 3RA0013333\n"
. " what is the status of invoice = 3RA0013333\n\n"
. "• Invoice type lookup:\n"
. " item = 674071 plant = Vahinie Unit 2\n"
. " item code = 674071 plant = Vahinie Unit 2\n\n"
. 'Any sentence containing keyword = value will work.';
}
}

View File

@@ -1,819 +0,0 @@
<?php
namespace App\Services;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Http;
use Illuminate\Support\Facades\Log;
/**
* GeminiChatbotService
* ─────────────────────────────────────────────────────────────────────────────
* Powers the "Advanced" chatbot mode with plain-English understanding.
*
* FLOW:
* 1. Takes the full chat history + new user message.
* 2. Sends them to Gemini with a structured system prompt.
* 3. Gemini returns JSON: { task, params, missing, clarification }.
* 4. If task is a known, complete query runs the matching DB handler.
* 5. If task is "unknown" sends the message to Gemini again as a free-form
* conversational assistant so it can answer or ask the user what they need.
* 6. If required params are missing Gemini's clarification question is returned.
*
* SUPPORTED TASKS:
* - invoice_status scan status of an invoice number
* - invoice_report serial/material invoice type for an item + plant
* - production_report production count for a plant / line / date range
* - unknown handled via a free-form Gemini conversation turn
*
* CONFIGURATION (.env):
* GEMINI_API_KEY=your_key_here
* GEMINI_MODEL=gemini-2.5-flash-preview set whichever model your key supports
*
* HOW TO ADD A NEW TASK:
* 1. Describe it in buildSystemPrompt() under TASKS.
* 2. Add a private handle*() method below.
* 3. Add a match arm in processMessage().
*/
class GeminiChatbotService
{
private string $apiKey;
/**
* Full REST endpoint model name is part of the URL path, e.g.:
* https://generativelanguage.googleapis.com/v1beta/models/gemini-2.5-flash-preview:generateContent
*
* Built in __construct() from config('services.gemini.model').
* Change GEMINI_MODEL in .env to switch models without editing code.
*/
private string $apiUrl;
public function __construct()
{
$this->apiKey = config('services.gemini.api_key', '');
$model = config('services.gemini.model', 'gemini-3-flash-preview');
$this->apiUrl = "https://generativelanguage.googleapis.com/v1beta/models/{$model}:generateContent";
}
// ─────────────────────────────────────────────────────────────────────────
// Public entry point
// ─────────────────────────────────────────────────────────────────────────
/**
* Process a user message in context of the prior conversation.
*
* @param array $chatHistory Previous turns: [['role'=>'user'|'assistant','content'=>'…'], ]
* @param string $userInput The new message just typed.
* @return string Plain-text reply to show in the chat bubble.
*/
public function processMessage(array $chatHistory, string $userInput): string
{
if (empty($this->apiKey)) {
return '⚠️ AI features are not configured. Please set GEMINI_API_KEY in your .env file.';
}
// ── Step 1: Classify the intent ───────────────────────────────────────
try {
$classification = $this->classifyWithGemini($chatHistory, $userInput);
} catch (\RuntimeException $e) {
// Surface the specific error directly in the chat bubble
return $e->getMessage();
}
$task = $classification['task'] ?? 'unknown';
$params = $classification['params'] ?? [];
$missing = $classification['missing'] ?? [];
$clarification = $classification['clarification'] ?? null;
// ── Step 2: Missing required params → ask user for them ───────────────
if (! empty($missing) && ! empty($clarification)) {
return $clarification;
}
// ── Step 3: Dispatch to the appropriate handler ───────────────────────
return match ($task) {
'invoice_status' => $this->handleInvoiceStatus($params),
'invoice_report' => $this->handleInvoiceReport($params),
'production_report' => $this->handleProductionReport($params),
// ── Unknown intent: hand off to Gemini as a free-form assistant ──
'unknown' => $this->handleUnknown($chatHistory, $userInput, $clarification),
default => $this->handleUnknown($chatHistory, $userInput, null),
};
}
// ─────────────────────────────────────────────────────────────────────────
// Gemini API calls
// ─────────────────────────────────────────────────────────────────────────
/**
* Phase 1 Classify the user's intent and extract structured params.
*
* @return array|null Parsed JSON array, or null on failure.
*/
/**
* @throws \RuntimeException with a user-facing message describing exactly what failed.
*/
private function classifyWithGemini(array $history, string $userInput): array
{
$requestBody = [
'system_instruction' => [
'parts' => [['text' => $this->buildSystemPrompt()]],
],
'contents' => $this->buildGeminiContents($history, $userInput),
'generationConfig' => [
'temperature' => 0.1,
'responseMimeType' => 'application/json',
],
];
// ── HTTP call ─────────────────────────────────────────────────────────
try {
$response = Http::withHeaders(['Content-Type' => 'application/json'])
->timeout(15)
->post($this->apiUrl . '?key=' . $this->apiKey, $requestBody);
} catch (\Exception $e) {
Log::error('GeminiChatbotService: HTTP exception', ['error' => $e->getMessage()]);
throw new \RuntimeException(
'⚠️ Could not reach the Gemini API. Check your network or firewall. ('
. $e->getMessage() . ')'
);
}
// ── HTTP-level error ──────────────────────────────────────────────────
if (! $response->successful()) {
$status = $response->status();
$body = $response->body();
Log::error('GeminiChatbotService: API HTTP error', [
'status' => $status,
'body' => $body,
]);
// Parse Google's error message when available
$googleMsg = $response->json('error.message') ?? $body;
throw new \RuntimeException(
"⚠️ Gemini API returned HTTP {$status}: {$googleMsg}"
);
}
// ── Extract text from response ────────────────────────────────────────
$text = $response->json('candidates.0.content.parts.0.text');
if (empty($text)) {
// Check for prompt-blocking
$blockReason = $response->json('promptFeedback.blockReason');
$finishReason = $response->json('candidates.0.finishReason');
Log::error('GeminiChatbotService: empty response text', [
'blockReason' => $blockReason,
'finishReason' => $finishReason,
'full' => $response->json(),
]);
$hint = $blockReason
? "prompt was blocked (reason: {$blockReason})"
: ($finishReason ? "finish reason: {$finishReason}" : 'no text returned');
throw new \RuntimeException("⚠️ Gemini returned no content — {$hint}");
}
// ── JSON decode ───────────────────────────────────────────────────────
$clean = preg_replace('/^```json\s*/i', '', trim($text));
$clean = preg_replace('/\s*```$/i', '', $clean);
$parsed = json_decode($clean, true);
if (json_last_error() !== JSON_ERROR_NONE) {
Log::error('GeminiChatbotService: JSON decode failed', ['raw' => $text]);
throw new \RuntimeException(
'⚠️ Gemini returned a non-JSON response: ' . mb_substr($text, 0, 200)
);
}
return $parsed;
}
/**
* Phase 2 (unknown task only) Ask Gemini to respond conversationally.
*
* Sends the full chat history + new user message to Gemini as a friendly
* factory-operations assistant (no JSON constraint). Gemini can ask for
* clarification, answer general questions, or guide the user to one of the
* supported tasks.
*
* @param string|null $hintFromClassification Optional clarification from the
* classification step prepended as assistant context if present.
* @return string Plain-text reply from Gemini.
*/
private function callGeminiConversational(
array $history,
string $userInput,
?string $hintFromClassification = null
): ?string {
// If the classifier already produced a good clarification question, use it
// directly and skip the second API call to save latency + quota.
if (! empty($hintFromClassification)) {
return $hintFromClassification;
}
$requestBody = [
'system_instruction' => [
'parts' => [['text' => $this->buildConversationalSystemPrompt()]],
],
'contents' => $this->buildGeminiContents($history, $userInput),
'generationConfig' => [
'temperature' => 0.7, // more natural conversational tone
'maxOutputTokens' => 400,
],
];
try {
$response = Http::withHeaders(['Content-Type' => 'application/json'])
->timeout(20)
->post($this->apiUrl . '?key=' . $this->apiKey, $requestBody);
if (! $response->successful()) {
Log::error('GeminiChatbotService: API error (conversational)', [
'status' => $response->status(),
'body' => $response->body(),
]);
return null;
}
return $response->json('candidates.0.content.parts.0.text');
} catch (\Exception $e) {
Log::error('GeminiChatbotService: exception (conversational)', ['error' => $e->getMessage()]);
return null;
}
}
// ─────────────────────────────────────────────────────────────────────────
// Prompt builders
// ─────────────────────────────────────────────────────────────────────────
/**
* System prompt for Phase 1 (classification) forces JSON output.
*/
private function buildSystemPrompt(): string
{
$today = now()->format('Y-m-d');
$startOfMonth = now()->startOfMonth()->format('Y-m-d');
return <<<PROMPT
You are a factory operations assistant that classifies plain-English user queries into structured tasks.
TASKS:
1. "invoice_status"
The user wants to check how many serial numbers in an invoice have been scanned / not scanned.
Required params: invoice_number
Examples:
- "check invoice 3RA0013333"
- "is invoice 3RA0013333 fully scanned?"
- "what's the scan status of 3RA0013333"
- "show me unscanned serials for invoice ABC123"
2. "invoice_report"
The user wants to know whether an item is a serial invoice or material invoice for a given plant.
Required params: item_code, plant_name
Examples:
- "check item 674071 for plant Vahinie Unit 2"
- "is item 500100 a serial or material invoice in Chennai plant?"
- "what type is item code 200300 at Vahinie?"
3. "production_report"
The user wants the production count for a plant and optional line over a date range.
Required params: plant_name
Optional params: line_name, date_from, date_to
Default dates: date_from = {$startOfMonth}, date_to = {$today}
Interpret relative dates: "this month", "last week", "yesterday", "today", etc.
Examples:
- "show production for Chennai plant this month"
- "how many units were produced in line 1 of Vahinie Unit 2 last week?"
- "production report for all plants from 2024-01-01 to 2024-01-31"
4. "unknown"
The query cannot be clearly matched to any of the above tasks.
Use this when the user is asking something general, greeting, asking what the bot can do,
asking a follow-up question that doesn't map to a task, or if you need more context.
In this case, set "clarification" to a friendly, helpful response it may be a question,
a helpful explanation, or guidance toward the supported tasks.
CONVERSATION CONTEXT:
Consider the full conversation history. If the previous assistant message asked a clarifying question
(e.g. "Do you mean Invoice Status or Invoice Report?") and the user is now answering that question,
classify accordingly based on the combined context.
OUTPUT FORMAT (return ONLY this JSON, no markdown fences, no extra text):
{
"task": "invoice_status | invoice_report | production_report | unknown",
"params": {
"invoice_number": "...",
"item_code": "...",
"plant_name": "...",
"line_name": "...",
"date_from": "YYYY-MM-DD",
"date_to": "YYYY-MM-DD"
},
"missing": ["list of required params that were not found in the user input"],
"clarification": "Friendly response for unknown tasks or missing-param prompts. Set to null when task is clear and params are complete."
}
RULES:
- Only include params relevant to the detected task.
- If a required param is missing, add it to "missing" and set a helpful "clarification" asking only for that missing value.
- If task is "unknown", always set "missing" to [] and put your full helpful response in "clarification".
- When task is clear and all required params are present, set "missing" to [] and "clarification" to null.
PROMPT;
}
/**
* System prompt for Phase 2 (conversational fallback) plain-text output.
*
* Used only when the classifier returns "unknown" AND produced no clarification.
*/
private function buildConversationalSystemPrompt(): string
{
return <<<PROMPT
You are a helpful factory operations assistant integrated into an internal management panel.
You can perform these tasks when the user gives you enough information:
Invoice Status check how many serial numbers in an invoice have been scanned and list any unscanned ones. Requires: invoice number.
Invoice Report find out whether an item is a serial invoice or material invoice for a given plant. Requires: item code and plant name.
Production Report get the production count for a plant, optionally filtered by line and date range. Requires: plant name.
When the user's request does not match any of the above:
- Answer general questions helpfully and concisely.
- If you need more information to perform a task, ask for only the missing detail.
- Guide the user toward one of the supported tasks when relevant.
- Keep replies short and conversational (2-4 sentences max).
- Do NOT mention JSON, APIs, or technical internals.
PROMPT;
}
/**
* Convert Livewire chat history + new user message into Gemini's contents array.
* Gemini uses "model" for the assistant role (not "assistant").
*/
private function buildGeminiContents(array $history, string $userInput): array
{
$contents = [];
// Include the last 8 turns at most to stay within token limits
foreach (array_slice($history, -8) as $msg) {
$contents[] = [
'role' => $msg['role'] === 'user' ? 'user' : 'model',
'parts' => [['text' => $msg['content']]],
];
}
$contents[] = [
'role' => 'user',
'parts' => [['text' => $userInput]],
];
return $contents;
}
// ─────────────────────────────────────────────────────────────────────────
// Task handlers
// ─────────────────────────────────────────────────────────────────────────
/**
* Invoice Status delegate to ChatbotService (regex-based, same as basic mode).
*/
private function handleInvoiceStatus(array $params): string
{
$invoiceNumber = trim(preg_replace('/\s+/', '', $params['invoice_number'] ?? ''));
if (empty($invoiceNumber)) {
return 'I need the invoice number to check the scan status. What is the invoice number?';
}
/** @var ChatbotService $svc */
$svc = app(ChatbotService::class);
return $svc->ask("invoice = {$invoiceNumber}");
}
/**
* Invoice Report resolves plant name with fuzzy matching, then runs the
* same CTE query as ChatBot::fetchInvoiceReport() directly.
*
* We bypass ChatbotService::ask() here so that resolvePlant()'s multi-strategy
* fuzzy logic is applied rather than the simpler LIKE inside ChatbotService.
*/
private function handleInvoiceReport(array $params): string
{
$itemCode = trim($params['item_code'] ?? '');
$plantName = trim($params['plant_name'] ?? '');
if (empty($itemCode)) {
return 'I need the item code to look up the invoice type. What is the item code?';
}
if (empty($plantName)) {
return 'I need the plant name to look up the invoice type. Which plant are you asking about?';
}
// ── Fuzzy-resolve the plant name ──────────────────────────────────────
$plant = $this->resolvePlant($plantName);
if ($plant === null) {
return "I couldn't find a plant matching \"{$plantName}\". "
. 'Please check the plant name and try again.';
}
// ── Run the same CTE as ChatBot::fetchInvoiceReport() ─────────────────
try {
$rows = DB::select("
WITH plant_item AS (
SELECT ? AS user_plant,
? AS user_item_code
),
t1 AS (
SELECT
plants.id AS plant_id,
plants.name AS plant_name,
ARRAY_AGG(items.code) AS item_codes
FROM plants
LEFT JOIN items ON plants.id = items.plant_id
GROUP BY plants.id, plants.name
),
t2 AS (
SELECT
t1.plant_id,
t1.plant_name,
CASE
WHEN plant_item.user_item_code = ANY(t1.item_codes) THEN 1
ELSE 0
END AS exists_flag
FROM t1
CROSS JOIN plant_item
WHERE t1.plant_name = plant_item.user_plant
),
t3 AS (
SELECT t2.plant_id, t2.plant_name, t2.exists_flag,
plant_item.user_item_code
FROM t2
LEFT JOIN plant_item ON plant_item.user_plant = t2.plant_name
),
t4 AS (
SELECT items.id AS item_id,
t3.plant_id, t3.plant_name, t3.exists_flag, t3.user_item_code
FROM t3
LEFT JOIN items
ON t3.plant_id = items.plant_id
AND t3.user_item_code = items.code
)
SELECT
t4.item_id,
t4.plant_id,
t4.plant_name,
t4.exists_flag,
t4.user_item_code,
COALESCE(sticker_masters.material_type, 0) AS material_type,
CASE
WHEN sticker_masters.item_id IS NULL
THEN 'no match found'
WHEN COALESCE(sticker_masters.material_type, 0) = 0
THEN 'serial invoice'
ELSE 'material invoice'
END AS invoice_description
FROM t4
LEFT JOIN sticker_masters
ON sticker_masters.plant_id = t4.plant_id
AND sticker_masters.item_id = t4.item_id
", [$plant->name, $itemCode]);
} catch (\Exception $e) {
Log::error('GeminiChatbotService: invoice report query failed', [
'plant' => $plant->name,
'item_code' => $itemCode,
'error' => $e->getMessage(),
]);
return "Sorry, I couldn't fetch data. Please try again or contact support.";
}
if (empty($rows)) {
return "No data found for plant \"{$plant->name}\". Please verify the plant name.";
}
$row = $rows[0];
if ((int) $row->exists_flag === 0) {
return 'The provided item code does not exist in the item table.';
}
return match ($row->invoice_description) {
'serial invoice' => 'It is a serial invoice item.',
'material invoice' => 'It is a material invoice item.',
'no match found' => "Item not found in sticker master for plant {$plant->name}.",
default => 'Unexpected result. Please contact support.',
};
}
/**
* Production Report resolves plant/line names to IDs and runs the count query.
* Mirrors ChatBot::fetchProduction() but works with plain names instead of IDs,
* using resolvePlant() for robust fuzzy matching.
*/
private function handleProductionReport(array $params): string
{
$plantName = trim($params['plant_name'] ?? '');
$lineName = trim($params['line_name'] ?? '');
$dateFrom = $params['date_from'] ?? now()->startOfMonth()->format('Y-m-d');
$dateTo = $params['date_to'] ?? now()->format('Y-m-d');
if (empty($plantName)) {
return 'I need a plant name to fetch the production report. Which plant are you asking about?';
}
// ── Fuzzy-resolve the plant name ──────────────────────────────────────
$plant = $this->resolvePlant($plantName);
if ($plant === null) {
return "I couldn't find a plant matching \"{$plantName}\". "
. 'Please check the plant name and try again.';
}
// ── Base query ────────────────────────────────────────────────────────
$query = DB::table('production_quantities')
->whereNull('deleted_at')
->where('plant_id', $plant->id)
->whereDate('created_at', '>=', $dateFrom)
->whereDate('created_at', '<=', $dateTo);
$lineLabel = 'All Lines';
// ── Optionally filter by line (fuzzy LIKE match) ──────────────────────
if (! empty($lineName)) {
$line = $this->resolveLine($lineName, $plant->id);
if ($line === null) {
return "I couldn't find a line matching \"{$lineName}\" "
. "in plant \"{$plant->name}\". Please check the line name.";
}
$query->where('line_id', $line->id);
$lineLabel = $line->name;
}
try {
$count = $query->count();
} catch (\Exception $e) {
Log::error('GeminiChatbotService: production query failed', [
'plant' => $plant->name,
'line' => $lineLabel,
'error' => $e->getMessage(),
]);
return "Sorry, I couldn't fetch production data for {$plant->name}. "
. 'Please try again or contact support.';
}
$from = \Carbon\Carbon::parse($dateFrom)->format('d M Y');
$to = \Carbon\Carbon::parse($dateTo)->format('d M Y');
return "📊 Production count for {$plant->name} / {$lineLabel} "
. "from {$from} to {$to}: {$count} records.";
}
// ─────────────────────────────────────────────────────────────────────────
// Fuzzy name resolvers
// ─────────────────────────────────────────────────────────────────────────
/**
* Resolve a user-supplied plant name to the best matching DB row.
*
* Strategy cascade (stops at first hit):
* 1. Exact case-insensitive match "ransar industries-i" == "Ransar Industries-I"
* 2. Normalised LIKE match strips hyphens/spaces, swaps I↔1
* 3. Every significant word present (LIKE) "ransar unit 2" matches "Ransar Industries Unit 2"
* 4. Best token-overlap score picks the DB row sharing the most words
*
* @return object|null stdClass with {id, name} or null if no match.
*/
private function resolvePlant(string $userInput): ?object
{
$allPlants = DB::table('plants')
->whereNull('deleted_at')
->get(['id', 'name']);
$norm = $this->normaliseForMatching($userInput);
// ── Strategy 1: exact normalised match ────────────────────────────────
foreach ($allPlants as $plant) {
if ($this->normaliseForMatching($plant->name) === $norm) {
return $plant;
}
}
// ── Strategy 2: normalised LIKE (user input contained in plant name or vice-versa) ──
foreach ($allPlants as $plant) {
$dbNorm = $this->normaliseForMatching($plant->name);
if (str_contains($dbNorm, $norm) || str_contains($norm, $dbNorm)) {
return $plant;
}
}
// ── Strategy 3: all significant user words appear in the plant name ───
$userTokens = $this->significantTokens($norm);
if (count($userTokens) >= 1) {
foreach ($allPlants as $plant) {
$dbNorm = $this->normaliseForMatching($plant->name);
$allFound = true;
foreach ($userTokens as $token) {
if (! str_contains($dbNorm, $token)) {
$allFound = false;
break;
}
}
if ($allFound) {
return $plant;
}
}
}
// ── Strategy 4: best token-overlap score ─────────────────────────────
$bestPlant = null;
$bestScore = 0;
foreach ($allPlants as $plant) {
$dbTokens = $this->significantTokens($this->normaliseForMatching($plant->name));
$shared = count(array_intersect($userTokens, $dbTokens));
// Require at least half the user tokens to match to avoid false positives
$threshold = max(1, (int) ceil(count($userTokens) / 2));
if ($shared >= $threshold && $shared > $bestScore) {
$bestScore = $shared;
$bestPlant = $plant;
}
}
return $bestPlant;
}
/**
* Resolve a user-supplied line name within a specific plant.
* Uses the same normalisation + token strategies as resolvePlant().
*
* @return object|null stdClass with {id, name} or null if no match.
*/
private function resolveLine(string $userInput, int $plantId): ?object
{
$allLines = DB::table('lines')
->whereNull('deleted_at')
->where('plant_id', $plantId)
->get(['id', 'name']);
$norm = $this->normaliseForMatching($userInput);
// Strategy 1: exact normalised
foreach ($allLines as $line) {
if ($this->normaliseForMatching($line->name) === $norm) {
return $line;
}
}
// Strategy 2: normalised LIKE
foreach ($allLines as $line) {
$dbNorm = $this->normaliseForMatching($line->name);
if (str_contains($dbNorm, $norm) || str_contains($norm, $dbNorm)) {
return $line;
}
}
// Strategy 3: all user tokens found in line name
$userTokens = $this->significantTokens($norm);
foreach ($allLines as $line) {
$dbNorm = $this->normaliseForMatching($line->name);
$allFound = true;
foreach ($userTokens as $token) {
if (! str_contains($dbNorm, $token)) {
$allFound = false;
break;
}
}
if ($allFound) {
return $line;
}
}
// Strategy 4: best token-overlap
$bestLine = null;
$bestScore = 0;
foreach ($allLines as $line) {
$dbTokens = $this->significantTokens($this->normaliseForMatching($line->name));
$shared = count(array_intersect($userTokens, $dbTokens));
$threshold = max(1, (int) ceil(count($userTokens) / 2));
if ($shared >= $threshold && $shared > $bestScore) {
$bestScore = $shared;
$bestLine = $line;
}
}
return $bestLine;
}
/**
* Normalise a plant/line name for fuzzy comparison:
* - lowercase
* - replace Roman numeral suffixes I/II/III/IV 1/2/3/4 (and vice-versa digits numerals as a canonical form)
* - collapse hyphens, underscores, extra spaces into a single space
* - strip leading/trailing whitespace
*
* Both the user input AND the DB value are passed through this before comparing,
* so the comparison is always apples-to-apples.
*/
private function normaliseForMatching(string $value): string
{
$v = strtolower($value);
// 1. Punctuation/separators → space
$v = str_replace(['-', '_', '.', ','], ' ', $v);
// 2. Split any letter→digit or digit→letter boundary with a space.
// e.g. "industries1" → "industries 1", "unit2" → "unit 2", "2unit" → "2 unit"
// This must happen BEFORE Roman numeral conversion so isolated digits are
// already separated from words.
$v = preg_replace('/([a-z])(\d)/', '$1 $2', $v);
$v = preg_replace('/(\d)([a-z])/', '$1 $2', $v);
// 3. Convert standalone Roman numerals to digits.
// Applied AFTER splitting so "industries" is never touched —
// the \b boundary ensures only whole tokens are matched.
// Order matters: longer patterns first (iii before ii before i).
$romanMap = [
'/\bviii\b/' => '8',
'/\bvii\b/' => '7',
'/\bvi\b/' => '6',
'/\biv\b/' => '4',
'/\biii\b/' => '3',
'/\bii\b/' => '2',
'/\bv\b/' => '5',
'/\bi\b/' => '1', // last — single i only after all others consumed
];
foreach ($romanMap as $pattern => $digit) {
$v = preg_replace($pattern, $digit, $v);
}
// 4. Collapse multiple spaces
$v = preg_replace('/\s+/', ' ', $v);
return trim($v);
}
/**
* Split a normalised string into significant tokens (drops noise words).
*
* @return array<string>
*/
private function significantTokens(string $normalised): array
{
$stopWords = ['and', 'the', 'of', 'for', 'at', 'in', 'a'];
$tokens = explode(' ', $normalised);
return array_values(array_filter($tokens, function (string $t) use ($stopWords) {
return strlen($t) >= 2 && ! in_array($t, $stopWords, true);
}));
}
// ─────────────────────────────────────────────────────────────────────────
/**
* Unknown task let Gemini respond conversationally.
*
* If the classification step already produced a useful clarification string
* (e.g. "Could you clarify — are you asking about scan status or invoice type?"),
* we return that directly without a second API call.
* Otherwise we hit Gemini again with a conversational system prompt.
*/
private function handleUnknown(
array $chatHistory,
string $userInput,
?string $clarificationFromClassifier
): string {
$reply = $this->callGeminiConversational(
$chatHistory,
$userInput,
$clarificationFromClassifier
);
return $reply
?? "I'm not sure I understood that. I can help you with:\n\n"
. "• Invoice Status — scan progress of an invoice\n"
. "• Invoice Report — serial vs material type for an item\n"
. "• Production Report — unit count for a plant / line\n\n"
. "What would you like to check?";
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -11,11 +11,9 @@
"althinect/filament-spatie-roles-permissions": "^2.3",
"diogogpinto/filament-auth-ui-enhancer": "^1.0",
"erag/laravel-pwa": "^1.9",
"ffhs/filament-package_ffhs_approvals": "^1.0",
"filament/filament": "^3.3",
"intervention/image": "^3.11",
"irazasyed/telegram-bot-sdk": "^3.15",
"laravel-notification-channels/webpush": "^10.4",
"laravel/framework": "^11.31",
"laravel/sanctum": "^4.0",
"laravel/tinker": "^2.9",

477
composer.lock generated
View File

@@ -4,7 +4,7 @@
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
"This file is @generated automatically"
],
"content-hash": "0e64d9b0a3c4d596ff8cd51b521c0565",
"content-hash": "69ede7e9877dd08efdeb795bfb6b7d29",
"packages": [
{
"name": "alperenersoy/filament-export",
@@ -1810,85 +1810,6 @@
},
"time": "2025-10-17T16:34:55+00:00"
},
{
"name": "ffhs/filament-package_ffhs_approvals",
"version": "1.0.1",
"source": {
"type": "git",
"url": "https://github.com/ffhs/filament-package_ffhs_approvals.git",
"reference": "712475522b63bf45a9e63a649d391cfe22132818"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/ffhs/filament-package_ffhs_approvals/zipball/712475522b63bf45a9e63a649d391cfe22132818",
"reference": "712475522b63bf45a9e63a649d391cfe22132818",
"shasum": ""
},
"require": {
"filament/filament": "^3.0",
"php": "^8.2",
"spatie/laravel-package-tools": "^1.15.0"
},
"require-dev": {
"larastan/larastan": "^3.0",
"laravel/pint": "^1.0",
"nunomaduro/collision": "^8.0",
"orchestra/testbench": "^9.9",
"pestphp/pest": "^3.7",
"pestphp/pest-plugin-arch": "^3.0",
"pestphp/pest-plugin-laravel": "^3.0",
"phpstan/extension-installer": "^1.1",
"phpstan/phpstan-deprecation-rules": "^2.0",
"phpstan/phpstan-phpunit": "^2.0",
"spatie/laravel-ray": "^1.26"
},
"type": "library",
"extra": {
"laravel": {
"aliases": {
"Approvals": "Ffhs\\Approvals\\Facades\\Approvals"
},
"providers": [
"Ffhs\\Approvals\\ApprovalsServiceProvider"
]
}
},
"autoload": {
"psr-4": {
"Ffhs\\Approvals\\": "src/",
"Ffhs\\Approvals\\Database\\Factories\\": "database/factories/"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Kromer Luc",
"email": "luc.kromer@ffhs.ch",
"role": "Developer"
},
{
"name": "Matthew Ballou",
"email": "mballou@kirschbaumdevelopment.com",
"role": "Developer"
}
],
"description": "This is my package filament-package_ffhs_approvals",
"homepage": "https://github.com/ffhs/filament-package_ffhs_approvals",
"keywords": [
"ffhs",
"filament-package_ffhs_approvals",
"kirschbaum-development",
"laravel"
],
"support": {
"issues": "https://github.com/ffhs/filament-package_ffhs_approvals/issues",
"source": "https://github.com/ffhs/filament-package_ffhs_approvals"
},
"time": "2025-07-24T14:32:41+00:00"
},
{
"name": "filament/actions",
"version": "v3.3.45",
@@ -3155,72 +3076,6 @@
},
"time": "2025-11-13T14:57:49+00:00"
},
{
"name": "laravel-notification-channels/webpush",
"version": "10.4.0",
"source": {
"type": "git",
"url": "https://github.com/laravel-notification-channels/webpush.git",
"reference": "a504bcbdd6258091b1fafdef6ca95b0891a47c9e"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/laravel-notification-channels/webpush/zipball/a504bcbdd6258091b1fafdef6ca95b0891a47c9e",
"reference": "a504bcbdd6258091b1fafdef6ca95b0891a47c9e",
"shasum": ""
},
"require": {
"illuminate/notifications": "^11.0|^12.0",
"illuminate/support": "^11.0|^12.0",
"minishlink/web-push": "^10.0",
"php": "^8.2"
},
"require-dev": {
"larastan/larastan": "^3.1",
"laravel/pint": "^1.25",
"mockery/mockery": "^1.0",
"orchestra/testbench": "^9.2|^10.0",
"phpunit/phpunit": "^10.5|^11.5.3",
"rector/rector": "^2.0"
},
"type": "library",
"extra": {
"laravel": {
"providers": [
"NotificationChannels\\WebPush\\WebPushServiceProvider"
]
}
},
"autoload": {
"psr-4": {
"NotificationChannels\\WebPush\\": "src"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Cretu Eusebiu",
"email": "me@cretueusebiu.com",
"homepage": "http://cretueusebiu.com",
"role": "Developer"
},
{
"name": "Joost de Bruijn",
"email": "joost@aqualabs.nl",
"role": "Maintainer"
}
],
"description": "Web Push Notifications driver for Laravel.",
"homepage": "https://github.com/laravel-notification-channels/webpush",
"support": {
"issues": "https://github.com/laravel-notification-channels/webpush/issues",
"source": "https://github.com/laravel-notification-channels/webpush/tree/10.4.0"
},
"time": "2025-12-19T15:47:27+00:00"
},
{
"name": "laravel/framework",
"version": "v11.46.1",
@@ -5025,73 +4880,6 @@
},
"time": "2019-10-05T02:44:33+00:00"
},
{
"name": "minishlink/web-push",
"version": "v10.0.1",
"source": {
"type": "git",
"url": "https://github.com/web-push-libs/web-push-php.git",
"reference": "08463189d3501cbd78a8625c87ab6680a7397aad"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/web-push-libs/web-push-php/zipball/08463189d3501cbd78a8625c87ab6680a7397aad",
"reference": "08463189d3501cbd78a8625c87ab6680a7397aad",
"shasum": ""
},
"require": {
"ext-curl": "*",
"ext-json": "*",
"ext-mbstring": "*",
"ext-openssl": "*",
"guzzlehttp/guzzle": "^7.9.2",
"php": ">=8.2",
"spomky-labs/base64url": "^2.0.4",
"web-token/jwt-library": "^3.4.9|^4.0.6"
},
"require-dev": {
"friendsofphp/php-cs-fixer": "^v3.91.3",
"phpstan/phpstan": "^2.1.33",
"phpstan/phpstan-strict-rules": "^2.0",
"phpunit/phpunit": "^11.5.46|^12.5.2",
"symfony/polyfill-iconv": "^1.33"
},
"suggest": {
"ext-bcmath": "Optional for performance.",
"ext-gmp": "Optional for performance."
},
"type": "library",
"autoload": {
"psr-4": {
"Minishlink\\WebPush\\": "src"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Louis Lagrange",
"email": "lagrange.louis@gmail.com",
"homepage": "https://github.com/Minishlink"
}
],
"description": "Web Push library for PHP",
"homepage": "https://github.com/web-push-libs/web-push-php",
"keywords": [
"Push API",
"WebPush",
"notifications",
"push",
"web"
],
"support": {
"issues": "https://github.com/web-push-libs/web-push-php/issues",
"source": "https://github.com/web-push-libs/web-push-php/tree/v10.0.1"
},
"time": "2025-12-15T10:04:28+00:00"
},
{
"name": "monolog/monolog",
"version": "3.9.0",
@@ -7908,180 +7696,6 @@
],
"time": "2025-09-24T06:40:28+00:00"
},
{
"name": "spomky-labs/base64url",
"version": "v2.0.4",
"source": {
"type": "git",
"url": "https://github.com/Spomky-Labs/base64url.git",
"reference": "7752ce931ec285da4ed1f4c5aa27e45e097be61d"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/Spomky-Labs/base64url/zipball/7752ce931ec285da4ed1f4c5aa27e45e097be61d",
"reference": "7752ce931ec285da4ed1f4c5aa27e45e097be61d",
"shasum": ""
},
"require": {
"php": ">=7.1"
},
"require-dev": {
"phpstan/extension-installer": "^1.0",
"phpstan/phpstan": "^0.11|^0.12",
"phpstan/phpstan-beberlei-assert": "^0.11|^0.12",
"phpstan/phpstan-deprecation-rules": "^0.11|^0.12",
"phpstan/phpstan-phpunit": "^0.11|^0.12",
"phpstan/phpstan-strict-rules": "^0.11|^0.12"
},
"type": "library",
"autoload": {
"psr-4": {
"Base64Url\\": "src/"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Florent Morselli",
"homepage": "https://github.com/Spomky-Labs/base64url/contributors"
}
],
"description": "Base 64 URL Safe Encoding/Decoding PHP Library",
"homepage": "https://github.com/Spomky-Labs/base64url",
"keywords": [
"base64",
"rfc4648",
"safe",
"url"
],
"support": {
"issues": "https://github.com/Spomky-Labs/base64url/issues",
"source": "https://github.com/Spomky-Labs/base64url/tree/v2.0.4"
},
"funding": [
{
"url": "https://github.com/Spomky",
"type": "github"
},
{
"url": "https://www.patreon.com/FlorentMorselli",
"type": "patreon"
}
],
"time": "2020-11-03T09:10:25+00:00"
},
{
"name": "spomky-labs/pki-framework",
"version": "1.4.1",
"source": {
"type": "git",
"url": "https://github.com/Spomky-Labs/pki-framework.git",
"reference": "f0e9a548df4e3942886adc9b7830581a46334631"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/Spomky-Labs/pki-framework/zipball/f0e9a548df4e3942886adc9b7830581a46334631",
"reference": "f0e9a548df4e3942886adc9b7830581a46334631",
"shasum": ""
},
"require": {
"brick/math": "^0.10|^0.11|^0.12|^0.13|^0.14",
"ext-mbstring": "*",
"php": ">=8.1"
},
"require-dev": {
"ekino/phpstan-banned-code": "^1.0|^2.0|^3.0",
"ext-gmp": "*",
"ext-openssl": "*",
"infection/infection": "^0.28|^0.29|^0.31",
"php-parallel-lint/php-parallel-lint": "^1.3",
"phpstan/extension-installer": "^1.3|^2.0",
"phpstan/phpstan": "^1.8|^2.0",
"phpstan/phpstan-deprecation-rules": "^1.0|^2.0",
"phpstan/phpstan-phpunit": "^1.1|^2.0",
"phpstan/phpstan-strict-rules": "^1.3|^2.0",
"phpunit/phpunit": "^10.1|^11.0|^12.0",
"rector/rector": "^1.0|^2.0",
"roave/security-advisories": "dev-latest",
"symfony/string": "^6.4|^7.0|^8.0",
"symfony/var-dumper": "^6.4|^7.0|^8.0",
"symplify/easy-coding-standard": "^12.0"
},
"suggest": {
"ext-bcmath": "For better performance (or GMP)",
"ext-gmp": "For better performance (or BCMath)",
"ext-openssl": "For OpenSSL based cyphering"
},
"type": "library",
"autoload": {
"psr-4": {
"SpomkyLabs\\Pki\\": "src/"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Joni Eskelinen",
"email": "jonieske@gmail.com",
"role": "Original developer"
},
{
"name": "Florent Morselli",
"email": "florent.morselli@spomky-labs.com",
"role": "Spomky-Labs PKI Framework developer"
}
],
"description": "A PHP framework for managing Public Key Infrastructures. It comprises X.509 public key certificates, attribute certificates, certification requests and certification path validation.",
"homepage": "https://github.com/spomky-labs/pki-framework",
"keywords": [
"DER",
"Private Key",
"ac",
"algorithm identifier",
"asn.1",
"asn1",
"attribute certificate",
"certificate",
"certification request",
"cryptography",
"csr",
"decrypt",
"ec",
"encrypt",
"pem",
"pkcs",
"public key",
"rsa",
"sign",
"signature",
"verify",
"x.509",
"x.690",
"x509",
"x690"
],
"support": {
"issues": "https://github.com/Spomky-Labs/pki-framework/issues",
"source": "https://github.com/Spomky-Labs/pki-framework/tree/1.4.1"
},
"funding": [
{
"url": "https://github.com/Spomky",
"type": "github"
},
{
"url": "https://www.patreon.com/FlorentMorselli",
"type": "patreon"
}
],
"time": "2025-12-20T12:57:40+00:00"
},
{
"name": "symfony/clock",
"version": "v7.3.0",
@@ -10890,95 +10504,6 @@
}
],
"time": "2024-11-21T01:49:47+00:00"
},
{
"name": "web-token/jwt-library",
"version": "4.1.3",
"source": {
"type": "git",
"url": "https://github.com/web-token/jwt-library.git",
"reference": "690d4dd47b78f423cb90457f858e4106e1deb728"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/web-token/jwt-library/zipball/690d4dd47b78f423cb90457f858e4106e1deb728",
"reference": "690d4dd47b78f423cb90457f858e4106e1deb728",
"shasum": ""
},
"require": {
"brick/math": "^0.12|^0.13|^0.14",
"php": ">=8.2",
"psr/clock": "^1.0",
"spomky-labs/pki-framework": "^1.2.1"
},
"conflict": {
"spomky-labs/jose": "*"
},
"suggest": {
"ext-bcmath": "GMP or BCMath is highly recommended to improve the library performance",
"ext-gmp": "GMP or BCMath is highly recommended to improve the library performance",
"ext-openssl": "For key management (creation, optimization, etc.) and some algorithms (AES, RSA, ECDSA, etc.)",
"ext-sodium": "Sodium is required for OKP key creation, EdDSA signature algorithm and ECDH-ES key encryption with OKP keys",
"paragonie/sodium_compat": "Sodium is required for OKP key creation, EdDSA signature algorithm and ECDH-ES key encryption with OKP keys",
"spomky-labs/aes-key-wrap": "For all Key Wrapping algorithms (AxxxKW, AxxxGCMKW, PBES2-HSxxx+AyyyKW...)",
"symfony/console": "Needed to use console commands",
"symfony/http-client": "To enable JKU/X5U support."
},
"type": "library",
"autoload": {
"psr-4": {
"Jose\\Component\\": ""
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Florent Morselli",
"homepage": "https://github.com/Spomky"
},
{
"name": "All contributors",
"homepage": "https://github.com/web-token/jwt-framework/contributors"
}
],
"description": "JWT library",
"homepage": "https://github.com/web-token",
"keywords": [
"JOSE",
"JWE",
"JWK",
"JWKSet",
"JWS",
"Jot",
"RFC7515",
"RFC7516",
"RFC7517",
"RFC7518",
"RFC7519",
"RFC7520",
"bundle",
"jwa",
"jwt",
"symfony"
],
"support": {
"issues": "https://github.com/web-token/jwt-library/issues",
"source": "https://github.com/web-token/jwt-library/tree/4.1.3"
},
"funding": [
{
"url": "https://github.com/Spomky",
"type": "github"
},
{
"url": "https://www.patreon.com/FlorentMorselli",
"type": "patreon"
}
],
"time": "2025-12-18T14:27:35+00:00"
}
],
"packages-dev": [

View File

@@ -18,11 +18,6 @@ return [
'token' => env('POSTMARK_TOKEN'),
],
'gemini' => [
'api_key' => env('GEMINI_API_KEY'),
'model' => env('GEMINI_MODEL', 'gemini-3-flash-preview'),
],
'ses' => [
'key' => env('AWS_ACCESS_KEY_ID'),
'secret' => env('AWS_SECRET_ACCESS_KEY'),

View File

@@ -12,23 +12,23 @@ return new class extends Migration
public function up(): void
{
$sql = <<<'SQL'
CREATE TABLE sticker_validations (
CREATE TABLE sticker_mapping_masters (
id BIGINT GENERATED always AS IDENTITY PRIMARY KEY,
plant_id BIGINT NOT NULL,
machine_id BIGINT NOT NULL,
production_order TEXT DEFAULT NULL,
serial_number TEXT DEFAULT NULL,
status TEXT DEFAULT NULL,
sticker_id TEXT DEFAULT NULL
plant_id BIGINT NOT NULL,
item_id BIGINT NOT NULL,
sticker1 TEXT DEFAULT NULL,
sticker2 TEXT DEFAULT NULL,
sticker3 TEXT DEFAULT NULL,
sticker4 TEXT DEFAULT NULL,
sticker5 TEXT DEFAULT NULL,
created_at TIMESTAMP NOT NULL DEFAULT NOW(),
updated_at TIMESTAMP NOT NULL DEFAULT NOW(),
created_by TEXT DEFAULT NULL,
updated_by TEXT DEFAULT NULL,
deleted_at TIMESTAMP,
FOREIGN KEY (plant_id) REFERENCES plants (id),
FOREIGN KEY (machine_id) REFERENCES machines (id)
FOREIGN KEY (plant_id) REFERENCES plants (id),
FOREIGN KEY (item_id) REFERENCES items(id)
);
SQL;
DB::statement($sql);
@@ -39,6 +39,6 @@ return new class extends Migration
*/
public function down(): void
{
Schema::dropIfExists('sticker_validations');
Schema::dropIfExists('sticker_mapping_masters');
}
};

View File

@@ -1,175 +0,0 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
return new class extends Migration
{
/**
* Run the migrations.
*/
public function up(): void
{
$sql = <<<'SQL'
CREATE TABLE item_characteristics (
id BIGINT GENERATED always AS IDENTITY PRIMARY KEY,
plant_id BIGINT NOT NULL,
item_id BIGINT NOT NULL,
class TEXT,
zz1_cn_bill_ord TEXT,
zmm_amps TEXT,
zmm_brand TEXT,
zmm_degreeofprotection TEXT,
zmm_delivery TEXT,
zmm_dir_rot TEXT,
zmm_discharge TEXT,
zmm_discharge_max TEXT,
zmm_discharge_min TEXT,
zmm_duty TEXT,
zmm_eff_motor TEXT,
zmm_eff_pump TEXT,
zmm_frequency TEXT,
zmm_head TEXT,
zmm_heading TEXT,
zmm_head_max TEXT,
zmm_head_minimum TEXT,
zmm_idx_eff_mtr TEXT,
zmm_idx_eff_pump TEXT,
zmm_kvacode TEXT,
zmm_maxambtemp TEXT,
zmm_mincoolingflow TEXT,
zmm_motorseries TEXT,
zmm_motor_model TEXT,
zmm_outlet TEXT,
zmm_phase TEXT,
zmm_pressure TEXT,
zmm_pumpflowtype TEXT,
zmm_pumpseries TEXT,
zmm_pump_model TEXT,
zmm_ratedpower TEXT,
zmm_region TEXT,
zmm_servicefactor TEXT,
zmm_servicefactormaximumamps TEXT,
zmm_speed TEXT,
zmm_suction TEXT,
zmm_suctionxdelivery TEXT,
zmm_supplysource TEXT,
zmm_temperature TEXT,
zmm_thrustload TEXT,
zmm_volts TEXT,
zmm_wire TEXT,
zmm_package TEXT,
zmm_pvarrayrating TEXT,
zmm_isi TEXT,
zmm_isimotor TEXT,
zmm_isipump TEXT,
zmm_isipumpset TEXT,
zmm_pumpset_model TEXT,
zmm_stages TEXT,
zmm_headrange TEXT,
zmm_overall_efficiency TEXT,
zmm_connection TEXT,
zmm_min_bore_size TEXT,
zmm_isireference TEXT,
zmm_category TEXT,
zmm_submergence TEXT,
zmm_capacitorstart TEXT,
zmm_capacitorrun TEXT,
zmm_inch TEXT,
zmm_motor_type TEXT,
zmm_dismantle_direction TEXT,
zmm_eff_ovrall TEXT,
zmm_bodymoc TEXT,
zmm_rotormoc TEXT,
zmm_dlwl TEXT,
zmm_inputpower TEXT,
zmm_imp_od TEXT,
zmm_ambtemp TEXT,
zmm_de TEXT,
zmm_dischargerange TEXT,
zmm_efficiency_class TEXT,
zmm_framesize TEXT,
zmm_impellerdiameter TEXT,
zmm_insulationclass TEXT,
zmm_maxflow TEXT,
zmm_minhead TEXT,
zmm_mtrlofconst TEXT,
zmm_nde TEXT,
zmm_powerfactor TEXT,
zmm_tagno TEXT,
zmm_year TEXT,
zmm_laser_name TEXT,
zmm_beenote TEXT,
zmm_beenumber TEXT,
zmm_beestar TEXT,
zmm_logo_ce TEXT,
zmm_codeclass TEXT,
zmm_colour TEXT,
zmm_logo_cp TEXT,
zmm_grade TEXT,
zmm_grwt_pset TEXT,
zmm_grwt_cable TEXT,
zmm_grwt_motor TEXT,
zmm_grwt_pf TEXT,
zmm_grwt_pump TEXT,
zmm_isivalve TEXT,
zmm_isi_wc TEXT,
zmm_labelperiod TEXT,
zmm_length TEXT,
zmm_license_cml_no TEXT,
zmm_mfgmonyr TEXT,
zmm_modelyear TEXT,
zmm_motoridentification TEXT,
zmm_newt_pset TEXT,
zmm_newt_cable TEXT,
zmm_newt_motor TEXT,
zmm_newt_pf TEXT,
zmm_newt_pump TEXT,
zmm_logo_nsf TEXT,
zmm_packtype TEXT,
zmm_panel TEXT,
zmm_performance_factor TEXT,
zmm_pumpidentification TEXT,
zmm_psettype TEXT,
zmm_size TEXT,
zmm_eff_ttl TEXT,
zmm_type TEXT,
zmm_usp TEXT,
zmm_1 TEXT,
zmm_2 TEXT,
zmm_3 TEXT,
zmm_4 TEXT,
zmm_5 TEXT,
zmm_6 TEXT,
zmm_7 TEXT,
zmm_8 TEXT,
zmm_9 TEXT,
zmm_10 TEXT,
zmm_11 TEXT,
zmm_12 TEXT,
zmm_13 TEXT,
zmm_14 TEXT,
zmm_15 TEXT,
created_at TIMESTAMP NOT NULL DEFAULT NOW(),
updated_at TIMESTAMP NOT NULL DEFAULT NOW(),
created_by TEXT DEFAULT NULL,
updated_by TEXT DEFAULT NULL,
deleted_at TIMESTAMP,
FOREIGN KEY (plant_id) REFERENCES plants (id),
FOREIGN KEY (item_id) REFERENCES items (id)
);
SQL;
DB::statement($sql);
}
/**
* Reverse the migrations.
*/
public function down(): void
{
Schema::dropIfExists('item_characteristics');
}
};

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