From 9aa585d8c9d9b77c50fb926ad8ad9e33ebb0f92d Mon Sep 17 00:00:00 2001 From: Yoga Pangestu Date: Thu, 4 Dec 2025 14:44:46 +0700 Subject: [PATCH] feat(company): implement custom company for 'Perusahaan' role - crud with custom page - create model and migration for database schema - custom view - company relation from User model --- app/Filament/Pages/CustomCompany.php | 307 ++++++++++++++++++ app/Models/Company.php | 33 ++ app/Models/User.php | 5 + ...25_11_20_041121_create_companies_table.php | 45 +++ .../views/filament/pages/company.blade.php | 9 + 5 files changed, 399 insertions(+) create mode 100644 app/Filament/Pages/CustomCompany.php create mode 100644 app/Models/Company.php create mode 100644 database/migrations/2025_11_20_041121_create_companies_table.php create mode 100644 resources/views/filament/pages/company.blade.php diff --git a/app/Filament/Pages/CustomCompany.php b/app/Filament/Pages/CustomCompany.php new file mode 100644 index 0000000..8548366 --- /dev/null +++ b/app/Filament/Pages/CustomCompany.php @@ -0,0 +1,307 @@ +user()->company; + + if (! $company) { + return; + } + + $this->company = $company; + + $this->form->fill($company->toArray()); + + $documents = [ + 'director_nik', + 'deed_incorporation', + 'trade_license', + 'tax_id_number', + 'taxable_enterprise', + 'annual_tax_return', + 'domicile_certificate', + 'profile', + ]; + + $mediaItems = $company->getMedia('companies'); + + foreach ($documents as $docType) { + $media = $mediaItems + ->where('custom_properties.doc_type', str($docType)->replace('_docs', '')->slug('-')) + ->sortByDesc('created_at') + ->first(); + + if ($media) { + $this->data["{$docType}_docs"] = [$media->getPathRelativeToRoot()]; + } + } + } + + public static function form(Schema $schema): Schema + { + $documents = [ + [ + 'title' => 'Akta Pendirian', + 'text_name' => 'deed_incorporation', + 'placeholder' => '*****', + 'max' => 100, + 'max_size' => 1024 * 10, + 'file_name' => 'deed_incorporation_docs', + 'accept' => ['application/pdf'], + 'folder' => 'companies/deed-incorporation/', + ], + [ + 'title' => 'SIUP / NIB', + 'text_name' => 'trade_license', + 'placeholder' => '*****', + 'max' => 100, + 'max_size' => 1024 * 10, + 'file_name' => 'trade_license_docs', + 'accept' => ['application/pdf'], + 'folder' => 'companies/trade-license/', + ], + [ + 'title' => 'NPWP', + 'text_name' => 'tax_id_number', + 'placeholder' => '*****', + 'max' => 100, + 'max_size' => 1024 * 10, + 'file_name' => 'tax_id_number_docs', + 'accept' => ['application/pdf'], + 'folder' => 'companies/tax-id-number/', + ], + [ + 'title' => 'PKP', + 'text_name' => 'taxable_enterprise', + 'placeholder' => '*****', + 'max' => 100, + 'max_size' => 1024 * 10, + 'file_name' => 'taxable_enterprise_docs', + 'accept' => ['application/pdf'], + 'folder' => 'companies/taxable-enterprise/', + ], + [ + 'title' => 'SPT Tahunan', + 'text_name' => 'annual_tax_return', + 'placeholder' => '*****', + 'max' => 100, + 'max_size' => 1024 * 10, + 'file_name' => 'annual_tax_return_docs', + 'accept' => ['application/pdf'], + 'folder' => 'companies/annual-tax-return/', + ], + [ + 'title' => 'Suket Domisili', + 'text_name' => 'domicile_certificate', + 'placeholder' => '*****', + 'max' => 100, + 'max_size' => 1024 * 10, + 'file_name' => 'domicile_certificate_docs', + 'accept' => ['application/pdf'], + 'folder' => 'companies/domicile-certificate/', + ], + [ + 'title' => 'Profil Perusahaan', + 'text_name' => 'profile', + 'placeholder' => '*****', + 'max' => 100, + 'max_size' => 1024 * 10, + 'file_name' => 'profile_docs', + 'accept' => ['application/pdf'], + 'folder' => 'companies/profile/', + ], + ]; + + return $schema + ->components([ + Section::make('Informasi') + ->schema([ + TextInput::make('name') + ->label('Nama') + ->placeholder('PT ABC Indonesia Abadi') + ->autocomplete(false) + ->autofocus() + ->required() + ->maxLength(100), + + TextInput::make('email') + ->label('Alamat Surel') + ->placeholder('johndoe@gmail.com') + ->autocomplete(false) + ->required() + ->maxLength(254), + + Textarea::make('address') + ->label('Alamat') + ->placeholder('Jl. Kebontoro, Jakarta Pusat') + ->autocomplete(false) + ->required() + ->columnSpanFull(), + + TextInput::make('director_name') + ->label('Nama Direktur') + ->placeholder('John Doe') + ->autocomplete(false) + ->required() + ->maxLength(100) + ->columnSpanFull(), + ]) + ->columns(2) + ->columnSpan(2), + + Group::make() + ->schema( + array_merge( + [ + Section::make('NIK Direktur') + ->schema([ + TextInput::make('director_nik') + ->hiddenLabel() + ->placeholder('32***') + ->autocomplete(false) + ->required() + ->maxLength(16) + ->rule('digits:16') + ->inputMode('numeric') + ->regex('/^[0-9]+$/'), + + AdvancedFileUpload::make('director_nik_docs') + ->hiddenLabel() + ->disk(config('filesystems.default')) + ->acceptedFileTypes(['images/*']) + ->maxSize(1024 * 3) + ->directory('companies/director-nik/'.now()->toDateString()), + ]), + ], + + collect($documents) + ->map( + fn ($doc) => Section::make($doc['title']) + ->schema([ + TextInput::make($doc['text_name']) + ->hiddenLabel() + ->placeholder($doc['placeholder']) + ->autocomplete(false) + ->required() + ->maxLength($doc['max']), + + AdvancedFileUpload::make($doc['file_name']) + ->hiddenLabel() + ->disk(config('filesystems.default')) + ->acceptedFileTypes($doc['accept']) + ->maxSize($doc['max_size']) + ->directory($doc['folder'].now()->toDateString()), + ]) + )->toArray() + ) + ) + ->columns(2), + ]) + ->statePath('data'); + } + + public function save() + { + $data = $this->form->getState(); + + $company = Company::updateOrCreate([ + 'id' => $this->company?->id, + ], [ + 'user_id' => auth()->id(), + 'name' => $data['name'], + 'email' => $data['email'], + 'address' => $data['address'], + 'director_name' => $data['director_name'], + 'director_nik' => $data['director_nik'], + 'deed_incorporation' => $data['deed_incorporation'], + 'trade_license' => $data['trade_license'], + 'tax_id_number' => $data['tax_id_number'], + 'taxable_enterprise' => $data['taxable_enterprise'], + 'annual_tax_return' => $data['annual_tax_return'], + 'domicile_certificate' => $data['domicile_certificate'], + 'profile' => $data['profile'], + ]); + + $this->company = $company; + + $documents = [ + 'director_nik_docs', + 'deed_incorporation_docs', + 'trade_license_docs', + 'tax_id_number_docs', + 'taxable_enterprise_docs', + 'annual_tax_return_docs', + 'domicile_certificate_docs', + 'profile_docs', + ]; + + foreach ($documents as $field) { + if (empty($this->data[$field])) { + continue; + } + + foreach ((array) $this->data[$field] as $filePath) { + $fullPath = Storage::disk(config('filesystems.default'))->path($filePath); + + if (! file_exists($fullPath)) { + continue; + } + + $company + ->addMediaFromDisk($filePath, config('filesystems.default')) + ->preservingOriginal() + ->withCustomProperties([ + 'feature' => 'companies', + 'date' => now()->toDateString(), + 'doc_type' => str($field) + ->replace('_docs', '') + ->slug('-'), + ]) + ->toMediaCollection('companies'); + } + } + + Notification::make() + ->title('Informasi perusahaan berhasil diperbarui.') + ->success() + ->send(); + } +} diff --git a/app/Models/Company.php b/app/Models/Company.php new file mode 100644 index 0000000..1bd0b85 --- /dev/null +++ b/app/Models/Company.php @@ -0,0 +1,33 @@ +belongsTo(User::class); + } + + public function parternMedia(): HasOne + { + return $this->hasOne(PartnerMedia::class); + } + + public function journalists(): HasManyThrough + { + return $this->hasManyThrough(Journalist::class, PartnerMedia::class); + } +} diff --git a/app/Models/User.php b/app/Models/User.php index 6a96e73..3e0e6f5 100644 --- a/app/Models/User.php +++ b/app/Models/User.php @@ -39,4 +39,9 @@ protected function withoutDeveloper(Builder $query): void $q->where('name', 'Developer'); }); } + + public function company(): HasOne + { + return $this->hasOne(Company::class); + } } diff --git a/database/migrations/2025_11_20_041121_create_companies_table.php b/database/migrations/2025_11_20_041121_create_companies_table.php new file mode 100644 index 0000000..4406979 --- /dev/null +++ b/database/migrations/2025_11_20_041121_create_companies_table.php @@ -0,0 +1,45 @@ +id(); + $table->foreignIdFor(User::class); + $table->string('name', 100); + $table->string('email', 254); + $table->text('address'); + $table->string('director_name', 100); + $table->string('director_nik', 16); + $table->string('deed_incorporation', 100); + $table->string('trade_license', 100); + $table->string('tax_id_number', 100); + $table->string('taxable_enterprise', 100); + $table->string('annual_tax_return', 100); + $table->string('domicile_certificate', 100); + $table->string('profile', 100); + $table->date('validated_at')->nullable(); + $table->text('rejection_reason')->nullable(); + $table->timestamp('created_at')->useCurrent(); + $table->timestamp('updated_at')->nullable()->useCurrentOnUpdate(); + $table->softDeletes(); + }); + } + + /** + * Reverse the migrations. + */ + public function down(): void + { + Schema::dropIfExists('companies'); + } +}; diff --git a/resources/views/filament/pages/company.blade.php b/resources/views/filament/pages/company.blade.php new file mode 100644 index 0000000..e5fc471 --- /dev/null +++ b/resources/views/filament/pages/company.blade.php @@ -0,0 +1,9 @@ + +
+ {{ $this->form }} + +
+ Simpan +
+
+