diff --git a/app/Filament/Imports/InvoiceValidationImporter.php b/app/Filament/Imports/InvoiceValidationImporter.php new file mode 100644 index 0000000..022c37b --- /dev/null +++ b/app/Filament/Imports/InvoiceValidationImporter.php @@ -0,0 +1,475 @@ +requiredMapping() + ->exampleHeader('PLANT CODE') + ->example('1000') + ->label('PLANT CODE') + ->relationship(resolveUsing: 'code') + ->rules(['required']), + ImportColumn::make('item_reference')// stickerMaster + ->requiredMapping() + ->exampleHeader('ITEM CODE') + ->example('123456') + ->label('ITEM CODE') + ->rules(['required']), + ImportColumn::make('invoice_number') + ->requiredMapping() + ->exampleHeader('INVOICE NUMBER') + ->example('RAW0009611') + ->label('INVOICE NUMBER') + ->rules(['required']), + ImportColumn::make('serial_number') + ->requiredMapping() + ->exampleHeader('SERIAL NUMBER') + ->example('12345678901234') + ->label('SERIAL NUMBER'), + ImportColumn::make('motor_scanned_status') + ->requiredMapping() + ->exampleHeader('MOTOR SCANNED STATUS') + ->example('1') + ->label('MOTOR SCANNED STATUS'), + ImportColumn::make('pump_scanned_status') + ->requiredMapping() + ->exampleHeader('PUMP SCANNED STATUS') + ->example('1') + ->label('PUMP SCANNED STATUS'), + ImportColumn::make('capacitor_scanned_status') + ->requiredMapping() + ->exampleHeader('CAPACITOR SCANNED STATUS') + ->example('1') + ->label('CAPACITOR SCANNED STATUS'), + ImportColumn::make('scanned_status_set') + ->requiredMapping() + ->exampleHeader('PUMPSET SCANNED STATUS') + ->example('') + ->label('PUMPSET SCANNED STATUS'), + ImportColumn::make('scanned_status') + ->requiredMapping() + ->exampleHeader('SCANNED STATUS') + ->example('Scanned') + ->label('SCANNED STATUS'), + ImportColumn::make('panel_box_code') + ->requiredMapping() + ->exampleHeader('PANEL BOX CODE') + ->example('PBOX0123') + ->label('PANEL BOX CODE'), + ImportColumn::make('panel_box_supplier') + ->requiredMapping() + ->exampleHeader('PANEL BOX SUPPLIER') + ->example('1900433') + ->label('PANEL BOX SUPPLIER'), + ImportColumn::make('panel_box_serial_number') + ->requiredMapping() + ->exampleHeader('PANEL BOX SERIAL NUMBER') + ->example('2512/101236') + ->label('PANEL BOX SERIAL NUMBER'), + ImportColumn::make('load_rate') + ->requiredMapping() + ->exampleHeader('LOAD RATE') + ->example('0') + ->label('LOAD RATE') + ->rules(['required']), + ImportColumn::make('upload_status') + ->requiredMapping() + ->exampleHeader('UPLOAD STATUS') + ->example('N') + ->label('UPLOAD STATUS') + ->rules(['required']), + ImportColumn::make('batch_number') + ->requiredMapping() + ->exampleHeader('BATCH NUMBER') + ->example('') + ->label('BATCH NUMBER'), + ImportColumn::make('quantity') + ->requiredMapping() + ->exampleHeader('QUANTITY') + ->example('') + ->label('QUANTITY'), + ImportColumn::make('operator_id') + ->requiredMapping() + ->exampleHeader('OPERATOR ID') + ->example('USER1') + ->label('OPERATOR ID') + ->rules(['required']), + ImportColumn::make('created_at') + ->requiredMapping() + ->exampleHeader('CREATED AT') + ->example('') + ->label('CREATED AT') + ->rules(['required']), + ImportColumn::make('created_by') + ->requiredMapping() + ->exampleHeader('CREATED BY') + ->example('USER1') + ->label('CREATED BY') + ->rules(['required']), + ImportColumn::make('updated_at') + ->requiredMapping() + ->exampleHeader('UPDATED AT') + ->example('USER1') + ->label('UPDATED AT') + ->rules(['required']), + ImportColumn::make('updated_by') + ->requiredMapping() + ->exampleHeader('UPDATED BY') + ->example('') + ->label('UPDATED BY') + ->rules(['required']), + ]; + } + + public function resolveRecord(): ?InvoiceValidation + { + // return InvoiceValidation::firstOrNew([ + // // Update existing records, matching them by `$this->data['column_name']` + // 'email' => $this->data['email'], + // ]); + + $warnMsg = []; + $plantId = null; + $stickId = null; + + $plantCod = $this->data['plant']; + $iCode = trim($this->data['item_reference']) ?? null; + $invoiceNumber = trim($this->data['invoice_number']) ?? null; + $serialNumber = trim($this->data['serial_number']) ?? null; + $curMotorQr = trim($this->data['motor_scanned_status']) ?? null; + $curPumpQr = trim($this->data['pump_scanned_status']) ?? null; + $curPumpSetQr = trim($this->data['scanned_status_set']) ?? null; + $curCapacitorQr = trim($this->data['capacitor_scanned_status']) ?? null; + $curScanStatus = trim($this->data['scanned_status']) ?? null; + $curPanelBoxCode = trim($this->data['panel_box_code']) ?? null; + $curPanelBoxSupplier = trim($this->data['panel_box_supplier']) ?? null; + $curPanelBoxSerialNumber = trim($this->data['panel_box_serial_number']) ?? null; + $loadRate = trim($this->data['load_rate']) ?? 0; + $uploadStatus = trim($this->data['upload_status']) ?? 'N'; + $batchNumber = null; // trim($this->data['batch_number']) ?? + $quantity = null; // trim($this->data['quantity']) ?? + $operatorId = trim($this->data['operator_id']); + $createdBy = trim($this->data['created_by']); + $updatedBy = trim($this->data['updated_by']); + $createdAt = $this->data['created_at']; + $updatedAt = $this->data['updated_at']; + + $packCnt = 0; + $scanCnt = 0; + $hasMotorQr = null; + $hasPumpQr = null; + $hasPumpSetQr = null; + $hasCapacitorQr = null; + $hadMotorQr = null; + $hadPumpQr = null; + $hadPumpSetQr = null; + $hadCapacitorQr = null; + + if ($plantCod == null || $plantCod == '') { + $warnMsg[] = "Plant code can't be empty!"; + } elseif ($iCode == null || $iCode == '') { + $warnMsg[] = "Item code can't be empty!"; + } elseif ($invoiceNumber == null || $invoiceNumber == '') { + $warnMsg[] = "Invoice number can't be empty!"; + } elseif ($serialNumber == null || $serialNumber == '') { + $warnMsg[] = "Serial number can't be empty!"; + } elseif ($curMotorQr != null && $curMotorQr != '' && $curMotorQr != '1' && $curMotorQr != 1) { + $warnMsg[] = 'Motor scanned status is invalid!'; + } elseif ($curPumpQr != null && $curPumpQr != '' && $curPumpQr != '1' && $curPumpQr != 1) { + $warnMsg[] = 'Pump scanned status is invalid!'; + } elseif ($curPumpSetQr != null && $curPumpSetQr != '' && $curPumpSetQr != '1' && $curPumpSetQr != 1) { + $warnMsg[] = 'PumpSet scanned status is invalid!'; + } elseif ($curCapacitorQr != null && $curCapacitorQr != '' && $curCapacitorQr != '1' && $curCapacitorQr != 1) { + $warnMsg[] = 'Capacitor scanned status is invalid!'; + } elseif ($curScanStatus != null && $curScanStatus != '' && $curScanStatus != 'Scanned') { + $warnMsg[] = 'Scanned status is invalid!'; + } elseif ($loadRate == null || $loadRate == '' || ! is_numeric($loadRate)) { + $warnMsg[] = 'Invalid load rate found!'; + } elseif ($uploadStatus != 'N' && $uploadStatus != 'Y') { + $warnMsg[] = 'Invalid upload status found!'; + } elseif ($operatorId == null || $operatorId == '') { + $warnMsg[] = "Operator ID can't be empty!"; + } elseif ($createdBy == null || $createdBy == '') { + $warnMsg[] = "Created by user can't be empty!"; + } elseif ($updatedBy == null || $updatedBy == '') { + $warnMsg[] = "Updated by user can't be empty!"; + } + + if (Str::length($plantCod) > 0 && (Str::length($plantCod) < 4 || ! is_numeric($plantCod) || ! preg_match('/^[1-9]\d{3,}$/', $plantCod))) { + $warnMsg[] = 'Invalid plant code found!'; + } elseif (Str::length($plantCod) > 0) { + $plant = Plant::where('code', $plantCod)->first(); + if (! $plant) { + $warnMsg[] = 'Plant code not found!'; + } else { + $plantId = $plant->id; + } + } + + if (Str::length($iCode) > 0 && (Str::length($iCode) < 6 || ! ctype_alnum($iCode))) { + $warnMsg[] = 'Invalid item code found!'; + } elseif ($plantId) { + $itemCode = Item::where('code', $iCode)->first(); + if (! $itemCode) { + $warnMsg[] = 'Item code not found in item master!'; + } else { + $itemCode = Item::where('code', $iCode)->where('plant_id', $plantId)->first(); + if (! $itemCode) { + $warnMsg[] = 'Item code not found in item master for the given plant!'; + } else { + $itemId = $itemCode->id; + $itemCode = StickerMaster::where('item_id', $itemId)->first(); + if (! $itemCode) { + $warnMsg[] = 'Item code not found in sticker master!'; + } else { + if ($plantId) { + $itemCode = StickerMaster::where('item_id', $itemId)->where('plant_id', $plantId)->first(); + if (! $itemCode) { + $warnMsg[] = 'Item code not found in sticker master for the given plant!'; + } elseif ($itemCode->material_type != '' && $itemCode->material_type != null) { + $stickId = null; + $warnMsg[] = 'Material invoice item code found!'; + } else { + $stickId = $itemCode->id; + $invalidPackage = false; + + $hasMotorQr = $itemCode->tube_sticker_motor ?? null; + $hasPumpQr = $itemCode->tube_sticker_pump ?? null; + $hasPumpSetQr = $itemCode->tube_sticker_pumpset ?? null; + $hasCapacitorQr = $itemCode->panel_box_code ?? null; + + if (! $hasMotorQr && ! $hasPumpQr && ! $hasPumpSetQr) {// && ! $hasCapacitorQr + $hasMotorQr = $itemCode->pack_slip_motor ?? null; + $hasPumpQr = $itemCode->pack_slip_pump ?? null; + $hasPumpSetQr = $itemCode->pack_slip_pumpset ?? null; + } else { + if (! $hasPumpSetQr && ! $hasPumpQr) { + $hasPumpQr = $itemCode->pack_slip_pump ?? null; + } + + $hasTubeMotorQr = $itemCode->tube_sticker_motor ?? null; + $hasPackMotorQr = $itemCode->pack_slip_motor ?? null; + $hasTubePumpSetQr = $itemCode->tube_sticker_pumpset ?? null; + $hasPackPumpSetQr = $itemCode->pack_slip_pumpset ?? null; + if ($hasTubeMotorQr != $hasPackMotorQr || $hasTubePumpSetQr != $hasPackPumpSetQr) { + $invalidPackage = true; + } + } + + if ((! $hasMotorQr && ! $hasPumpQr && ! $hasPumpSetQr && ! $hasCapacitorQr) || $invalidPackage) { + $stickId = null; + $warnMsg[] = "Item code doesn't have valid package type to proceed!"; + } else { + if ($hasMotorQr) { + $packCnt++; + } + if ($hasPumpQr) { + $packCnt++; + } + if ($hasPumpSetQr) { + $packCnt++; + } + if ($hasCapacitorQr) { + $packCnt++; + } + // if ($hasMotorQr || $hasPumpQr || $hasPumpSetQr || $hasCapacitorQr) { + // $packCnt = $hasMotorQr ? $packCnt + 1 : $packCnt; + // $packCnt = $hasPumpQr ? $packCnt + 1 : $packCnt; + // $packCnt = $hasPumpSetQr ? $packCnt + 1 : $packCnt; + // $packCnt = $hasCapacitorQr ? $packCnt + 1 : $packCnt; + // } + } + } + } + } + } + } + } + + if ($stickId) { + if (! $hasMotorQr) { + $curMotorQr = null; + } + if (! $hasPumpQr) { + $curPumpQr = null; + } + if (! $hasPumpSetQr) { + $curPumpSetQr = null; + } + if (! $hasCapacitorQr) { + $curCapacitorQr = null; + $curPanelBoxCode = null; + $curPanelBoxSupplier = null; + $curPanelBoxSerialNumber = null; + } + + $record = InvoiceValidation::where('serial_number', $serialNumber) + ->where('plant_id', $plantId) + ->whereHas('stickerMasterRelation.item', function ($query) use ($plantId, $iCode) { + $query->where('plant_id', $plantId)->where('code', $iCode); + }) + ->first(); + + $invalidPackage = false; + + if ($record) { + + $hadMotorQr = $record->motor_scanned_status ?? null; + $hadPumpQr = $record->pump_scanned_status ?? null; + $hadPumpSetQr = $record->scanned_status_set ?? null; + $hadCapacitorQr = $record->capacitor_scanned_status ?? null; + + if ($hadMotorQr) { + $curMotorQr = $hadMotorQr; + } + if ($hadPumpQr) { + $curPumpQr = $hadPumpQr; + } + if ($hadPumpSetQr) { + $curPumpSetQr = $hadPumpSetQr; + } + if ($hadCapacitorQr) { + $curCapacitorQr = $hadCapacitorQr; + $curPanelBoxCode = $record->panel_box_code ?? null; + $curPanelBoxSupplier = $record->panel_box_supplier ?? null; + $curPanelBoxSerialNumber = $record->panel_box_serial_number ?? null; + } + + // if ($hadPumpQr == $hasPumpQr && $hadPumpSetQr == $hasPumpSetQr) + if ($hasMotorQr || $hasPumpQr || $hasPumpSetQr || $hasCapacitorQr) { + $scanCnt = $curMotorQr ? $scanCnt + 1 : $scanCnt; + $scanCnt = $curPumpQr ? $scanCnt + 1 : $scanCnt; + $scanCnt = $curPumpSetQr ? $scanCnt + 1 : $scanCnt; + $scanCnt = $curCapacitorQr ? $scanCnt + 1 : $scanCnt; + + $record->motor_scanned_status = $curMotorQr; + $record->pump_scanned_status = $curPumpQr; + $record->scanned_status_set = $curPumpSetQr; + $record->capacitor_scanned_status = $curCapacitorQr; + $record->panel_box_code = $curPanelBoxCode; + $record->panel_box_supplier = $curPanelBoxSupplier; + $record->panel_box_serial_number = $curPanelBoxSerialNumber; + if ($packCnt == $scanCnt) { + $record->scanned_status = 'Scanned'; + } + $record->updated_by = $updatedBy; + $record->save(); + + return null; + } + } + } + + if ($stickId) { + $formats = ['d-m-Y H:i', 'd-m-Y H:i:s']; // '07-05-2025 08:00' or '07-05-2025 08:00:00' + $cDateTime = null; + $uDateTime = null; + + foreach ($formats as $format) { + try { + $cDateTime = Carbon::createFromFormat($format, $createdAt); + break; + } catch (\Exception $e) { + // $warnMsg[] = "Date format mismatch with format: $format"; + } + } + + foreach ($formats as $format) { + try { + $uDateTime = Carbon::createFromFormat($format, $updatedAt); + break; + } catch (\Exception $e) { + // $warnMsg[] = "Date format mismatch with format: $format"; + } + } + + if (! isset($cDateTime)) { + $warnMsg[] = "Invalid 'Created DateTime' format. Expected DD-MM-YYYY HH:MM:SS"; + } + if (! isset($uDateTime)) { + $warnMsg[] = "Invalid 'Updated DateTime' format. Expected DD-MM-YYYY HH:MM:SS"; + } + + if (isset($cDateTime) && isset($uDateTime)) { + if ($cDateTime->greaterThan($uDateTime)) { + $warnMsg[] = "'Created DataTime' is greater than 'Updated DateTime'."; + } + } + } + + if (! empty($warnMsg)) { + throw new RowImportFailedException(implode(', ', $warnMsg)); + } + + if ($hasMotorQr || $hasPumpQr || $hasPumpSetQr || $hasCapacitorQr) { + $scanCnt = $curMotorQr ? $scanCnt + 1 : $scanCnt; + $scanCnt = $curPumpQr ? $scanCnt + 1 : $scanCnt; + $scanCnt = $curPumpSetQr ? $scanCnt + 1 : $scanCnt; + $scanCnt = $curCapacitorQr ? $scanCnt + 1 : $scanCnt; + + if ($packCnt == $scanCnt) { + $curScanStatus = 'Scanned'; + } else { + $curScanStatus = null; + } + } + // $curScanStatus + + return InvoiceValidation::updateOrCreate([ + 'plant_id' => $plantId, + 'sticker_master_id' => $stickId, + 'serial_number' => $serialNumber, + ], + [ + 'invoice_number' => $invoiceNumber, + 'motor_scanned_status' => $curMotorQr, + 'pump_scanned_status' => $curPumpQr, + 'scanned_status_set' => $curPumpSetQr, + 'capacitor_scanned_status' => $curCapacitorQr, + 'panel_box_code' => $curPanelBoxCode, + 'panel_box_supplier' => $curPanelBoxSupplier, + 'panel_box_serial_number' => $curPanelBoxSerialNumber, + 'scanned_status' => $curScanStatus, + 'load_rate' => $loadRate, + 'upload_status' => $uploadStatus, + 'batch_number' => null, + 'quantity' => null, + 'operator_id' => $operatorId, + 'created_by' => $createdBy, + 'updated_by' => $updatedBy, + 'created_at' => $cDateTime->format('Y-m-d H:i:s'), + 'updated_at' => $uDateTime->format('Y-m-d H:i:s'), + ]); + + // return new InvoiceValidation; + } + + public static function getCompletedNotificationBody(Import $import): string + { + $body = 'Your invoice validation 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; + } +} diff --git a/app/Filament/Resources/InvoiceValidationResource.php b/app/Filament/Resources/InvoiceValidationResource.php index fb02a38..0b67e18 100644 --- a/app/Filament/Resources/InvoiceValidationResource.php +++ b/app/Filament/Resources/InvoiceValidationResource.php @@ -4,6 +4,7 @@ namespace App\Filament\Resources; use AlperenErsoy\FilamentExport\Actions\FilamentExportBulkAction; use App\Filament\Exports\InvoiceValidationExporter; +use App\Filament\Imports\InvoiceValidationImporter; use App\Filament\Resources\InvoiceValidationResource\Pages; use App\Mail\InvoiceNotification; use App\Models\InvoiceValidation; @@ -27,6 +28,7 @@ use Filament\Resources\Resource; use Filament\Tables; use Filament\Tables\Actions\Action; use Filament\Tables\Actions\ExportAction; +use Filament\Tables\Actions\ImportAction; use Filament\Tables\Filters\Filter; use Filament\Tables\Table; use Illuminate\Database\Eloquent\Builder; @@ -1125,6 +1127,13 @@ class InvoiceValidationResource extends Resource ->visible(function () { return Filament::auth()->user()->can('view import material invoice'); }), + ImportAction::make() + ->label('Import Invoices') + ->color('warning') + ->importer(InvoiceValidationImporter::class) + ->visible(function () { + return Filament::auth()->user()->can('view import invoice'); + }), ExportAction::make() ->label('Export Invoices') ->color('warning') diff --git a/database/seeders/PermissionSeeder.php b/database/seeders/PermissionSeeder.php index 4093d06..0c1a23e 100644 --- a/database/seeders/PermissionSeeder.php +++ b/database/seeders/PermissionSeeder.php @@ -90,6 +90,7 @@ class PermissionSeeder extends Seeder Permission::updateOrCreate(['name' => 'view import serial invoice']); Permission::updateOrCreate(['name' => 'view import material invoice']); + Permission::updateOrCreate(['name' => 'view import invoice']); Permission::updateOrCreate(['name' => 'view export invoice']); Permission::updateOrCreate(['name' => 'view import locator invoice validation']); diff --git a/routes/api.php b/routes/api.php index 147a7a7..c18df10 100644 --- a/routes/api.php +++ b/routes/api.php @@ -33,9 +33,9 @@ use App\Http\Controllers\StickerMasterController; // use App\Http\Controllers\TelegramController; use App\Http\Controllers\TestingPanelController; use App\Http\Controllers\UserController; -use App\Http\Controllers\VehicleController; -use Illuminate\Foundation\Http\Middleware\VerifyCsrfToken; -use Illuminate\Http\Request; +// use App\Http\Controllers\VehicleController; +// use Illuminate\Foundation\Http\Middleware\VerifyCsrfToken; +// use Illuminate\Http\Request; use Illuminate\Support\Facades\Route; // Route::get('/user', function (Request $request) { @@ -215,6 +215,6 @@ Route::post('file/store', [SapFileController::class, 'store'])->name('file.store // Route::post('invoice-exit', [InvoiceValidationController::class, 'handle']); -Route::get('/print-pallet/{pallet}/{plant}', [PalletPrintController::class, 'print'])->name('print.pallet'); +// Route::get('/print-pallet/{pallet}/{plant}', [PalletPrintController::class, 'print'])->name('print.pallet'); -Route::post('vehicle/entry', [VehicleController::class, 'storeVehicleEntry']); +// Route::post('vehicle/entry', [VehicleController::class, 'storeVehicleEntry']);