Compare commits

..

74 Commits

Author SHA1 Message Date
arifal
34e082c31b fix bug sync google sheet and handle to long data address on pbg task 2025-05-20 11:13:21 +07:00
arifal
c4d865bf2b fix get menu id and height auto chart growth 2025-05-15 18:09:28 +07:00
arifal
a103b38265 create page growth report 2025-05-15 17:02:02 +07:00
arifal
9aa3d32b6e add link in potential dashboard 2025-05-15 14:18:27 +07:00
arifal
99e2c214b6 create redirect link for dashboard pimpinan 2025-05-14 20:56:36 +07:00
arifal
501a76bc81 partial update circle chart can click 2025-05-06 17:29:39 +07:00
arifal
460267992e handle null value on detail quick search 2025-05-06 15:32:03 +07:00
arifal
becc368069 last update feat quick search 2025-05-06 15:06:59 +07:00
arifal
2618ac06d0 partial update create page quick search 2025-05-05 18:36:56 +07:00
arifal
d95676d477 fix show page document pbg 2025-04-10 15:44:51 +07:00
arifal
7737fee30f add validation topic on send prompt if not relevan 2025-04-10 01:59:57 +07:00
arifal
48293386c7 fix change chatbot to top 2025-04-09 21:22:26 +07:00
arifal
84870b95b1 add feat upload pbg task 2025-04-09 21:10:20 +07:00
arifal
6294d2f950 add new users on seeder for role user and superadmin 2025-03-27 17:19:27 +07:00
arifal
7b70591be5 add readme and backup schema local 2025-03-27 15:28:21 +07:00
arifal
3b67bfd1fb remove duplicate use timeout when running queue 2025-03-26 15:20:03 +07:00
arifal
45e22096ed add column to model import datasources 2025-03-26 11:51:57 +07:00
arifal
c7a8d6d249 add condition show button retry 2025-03-25 22:46:34 +07:00
arifal
091b1f305e fix handle retry button 2025-03-25 15:54:02 +07:00
arifal
e7950e22f2 add flatpicker for edit pbg task data 2025-03-24 21:16:05 +07:00
arifal
b68641db03 backup local db and add global setting seeder to run default 2025-03-24 11:08:10 +07:00
arifal
fefb85ac7a remove get sample data from service 2025-03-21 19:10:17 +07:00
arifal
d28a08a24c fix add bigdata resume after syncronize 2025-03-21 19:08:18 +07:00
arifal
654d2efe19 fix syncronize using worker and add duration syncronize 2025-03-21 18:44:28 +07:00
arifal
0a080763cd try catch handle refresh token fail to login again 2025-03-21 16:03:10 +07:00
arifal
f3ef21d1be fix style error message when failed login 2025-03-21 15:10:28 +07:00
arifal
d7bff86741 fix menu with parent data and remove action google sheet not available feature 2025-03-21 14:54:18 +07:00
arifal
f36f250700 fix supervisorctl syntax on deploy 2025-03-20 20:19:38 +07:00
arifal
2c5da87856 fix reload php service on deploy 2025-03-20 20:18:09 +07:00
arifal
a195559c4b fix running syntax seeder on automation deploy syntax 2025-03-20 20:15:30 +07:00
arifal
088f173fec fix add params filter date on grid js, export excel and pdf payment recaps 2025-03-20 20:12:42 +07:00
arifal
eadfddb3a4 add export excel and pdf district payment recaps 2025-03-19 18:55:51 +07:00
arifal
47a9fb1dfb add export excel and pdf report director 2025-03-19 18:22:00 +07:00
arifal
1713e32b67 add export pdf report tourisms and report ptsp 2025-03-19 17:15:10 +07:00
arifal
cf998455e0 add export excel report tourisms 2025-03-19 16:16:10 +07:00
arifal
5e1c9f3a2e fix dashboard pbg, add soft delete users, fix js create pbg task 2025-03-19 14:06:10 +07:00
arifal
e940b8d6c7 fix handle sync using button 2025-03-18 08:10:06 +07:00
arifal
5e139bc29c change command scraping 2025-03-18 06:47:53 +07:00
arifal
f9e1aa1604 fix service scraping data 2025-03-18 06:42:42 +07:00
arifal
2e385f80cd fix optimize syncronize 2025-03-14 19:10:28 +07:00
arifal
e2c26e0eff fix reklame route index 2025-03-13 16:23:17 +07:00
arifal
ca5b8ad403 fix deploy code and readme 2025-03-13 15:59:11 +07:00
arifal
e97b7eb70d fix redirect back spatial plannings 2025-03-13 15:48:53 +07:00
arifal
0258ca9f04 fix redirect back umkm 2025-03-13 15:39:32 +07:00
arifal
0116147e06 fix redirect back reklame and tourisms 2025-03-13 15:24:59 +07:00
arifal
7787db02a3 fix redirect back business or industries 2025-03-13 14:13:06 +07:00
arifal
e47ab36d5e fix pdam redirect back and advertisement partial update redirect 2025-03-13 13:57:53 +07:00
arifal
e5db2294b4 fix redirect back data settings 2025-03-12 21:39:52 +07:00
arifal
4db457d7bd fix redirect back users crud 2025-03-12 21:17:49 +07:00
arifal
7a82ad5302 fix redirect back roles 2025-03-12 20:30:16 +07:00
arifal
b0d4d4c23b fix redirect back with params menu id 2025-03-12 17:52:11 +07:00
arifal
68ffc1c090 fix 503 page 2025-03-12 15:57:31 +07:00
arifal
a1f4bd7f81 fix seeder menu role and user assign, create 503 page and fix redirect home 2025-03-12 15:37:22 +07:00
arifal
238aaba96c fix seeder users role menu 2025-03-12 12:01:28 +07:00
arifal
c7152d9dbe fix resources report payment recaps 2025-03-12 11:50:56 +07:00
arifal
2a4b96d0b2 fix vite resources 2025-03-12 11:43:11 +07:00
arifal
dd940ebdb6 fix inside and outside dashboard 2025-03-12 11:38:07 +07:00
arifal
dce5409248 done all view dummy new modul 2025-03-12 00:32:50 +07:00
arifal
b8f7d7f655 fix back button 2025-03-11 01:17:16 +07:00
arifal
65600f1b4f add view list data from google sheet 2025-03-11 00:26:48 +07:00
arifal
b0f15a9221 fix sidebar permission user 2025-03-10 16:33:53 +07:00
arifal
bf55eb228e fix width dashboard outside sy system and loading when load maps pariwisata, backup localdb 2025-03-07 18:00:30 +07:00
arifal
755720bac9 fix failed build images from leaflet 2025-03-07 16:41:52 +07:00
arifal
098b4c605b fix missing scss on vite 2025-03-07 15:39:26 +07:00
arifal
4632e102eb add use package missing 2025-03-07 15:00:26 +07:00
arifal
0431945a42 fix conflict 2025-03-07 14:52:51 +07:00
arifal
c529a5d511 add readme 2025-03-07 14:39:23 +07:00
arifal
ff244039ff add readme and env example 2025-03-07 14:37:26 +07:00
arifal
55902042f4 add readme 2025-03-07 14:27:49 +07:00
arifal
c67aa979c2 change column type expertise and fix syncronize simbg service 2025-03-07 14:04:37 +07:00
arifal
fbaa33ae13 fix height scrollbar table grid js 2025-03-07 01:55:46 +07:00
arifal
9516b6f575 fix task assignment table on pbg task 2025-03-07 01:03:22 +07:00
arifal
ffc08f26cc add dashboard inside and outside system and fix timeout when search filter 2025-03-06 23:33:31 +07:00
arifal
e0c35b8897 fix search filter on page big data resume 2025-03-06 14:39:36 +07:00
235 changed files with 10358 additions and 2909 deletions

View File

@@ -67,4 +67,5 @@ AWS_USE_PATH_STYLE_ENDPOINT=false
VITE_APP_NAME="${APP_NAME}"
API_KEY_GOOGLE="xxxxx"
SPREAD_SHEET_ID="xxxxx"
SPREAD_SHEET_ID="xxxxx"
OPENAI_API_KEY="xxxxx"

View File

@@ -17,13 +17,14 @@ sudo nano /etc/supervisor/conf.d/laravel-worker.conf
[program:laravel-worker]
process_name=%(program_name)s_%(process_num)02d
command=php /path-to-your-project/artisan queue:work --tries=3 --timeout=600
command=php /home/arifal/development/sibedas-pbg-web/artisan queue:work --queue=default --timeout=82800 --tries=1
autostart=true
autorestart=true
numprocs=1
user=www-data
redirect_stderr=true
stdout_logfile=/var/log/supervisor/laravel-worker.log
stdout_logfile=/home/arifal/development/sibedas-pbg-web/storage/logs/worker.log
stopasgroup=true
killasgroup=true
```
- Reload Supervisor
@@ -35,3 +36,77 @@ sudo supervisorctl start laravel-worker
sudo supervisorctl restart laravel-worker
sudo supervisorctl status
```
# How to running
- Install composer package
```
composer install
```
- Install npm package
```
npm install && npm run build
```
- Create symlinks storage
```
php artisan storage:link
```
- Running migration
```
php artisan migrate
```
- Running seeder
```
php artisan db:seed
```
- Create view table
- excute all sql queries on folder database/view_query
# Add ENV variable
- API_KEY_GOOGLE
```
Get api key from google developer console for and turn on spreadsheet api or feaature for google sheet
```
- SPREAD_SHEET_ID
```
Get spreadsheet id from google sheet link
```
- OPENAI_API_KEY
```
Get OpenAI API key from chatgpt subscription
```
- ENV
```
API_KEY_GOOGLE="xxxxx"
SPREAD_SHEET_ID="xxxxx"
OPENAI_API_KEY="xxxxx"
```
# Technology version
- php 8.3
- Laravel 11
- node v22.13.0
- npm 10.9.2
- mariadb Ver 15.1 Distrib 10.6.18-MariaDB, for debian-linux-gnu (x86_64) using EditLine wrapper
- Ubuntu 24.04

View File

@@ -34,7 +34,7 @@ class ExecuteScraping extends Command
}
public function handle()
{
SyncronizeSIMBG::dispatch();
SyncronizeSIMBG::dispatch()->onQueue('default');
Log::info("running scheduler daily scraping");
}
}

View File

@@ -0,0 +1,95 @@
<?php
namespace App\Console\Commands;
use App\Jobs\ScrapingDataJob;
use App\Models\ImportDatasource;
use App\Services\ServiceGoogleSheet;
use App\Services\ServicePbgTask;
use App\Services\ServiceTabPbgTask;
use App\Services\ServiceTokenSIMBG;
use GuzzleHttp\Client; // Import Guzzle Client
use Illuminate\Console\Command;
use Illuminate\Support\Facades\Log;
use Illuminate\Support\Facades\DB;
class ScrapingData extends Command
{
/**
* The name and signature of the console command.
*
* @var string
*/
protected $signature = 'app:scraping-data';
/**
* The console command description.
*
* @var string
*/
protected $description = 'Command description';
/**
* Inject dependencies.
*/
public function __construct(
) {
parent::__construct();
}
public function handle()
{
dispatch(new ScrapingDataJob());
$this->info("Scraping job dispatched successfully");
}
/**
* Execute the console command.
*/
// public function handle()
// {
// try {
// // Create a record with "processing" status
// $import_datasource = ImportDatasource::create([
// 'message' => 'Initiating scraping...',
// 'response_body' => null,
// 'status' => 'processing',
// 'start_time' => now()
// ]);
// // Run the service
// $service_google_sheet = new ServiceGoogleSheet();
// $service_google_sheet->run_service();
// // Run the ServicePbgTask with injected Guzzle Client
// $this->service_pbg_task->run_service();
// // run the service pbg task assignments
// $this->service_tab_pbg_task->run_service();
// // Update the record status to "success" after completion
// $import_datasource->update([
// 'status' => 'success',
// 'message' => 'Scraping completed successfully.',
// 'finish_time' => now()
// ]);
// } catch (\Exception $e) {
// // Log the error for debugging
// Log::error('Scraping failed: ' . $e->getMessage(), ['trace' => $e->getTraceAsString()]);
// // Handle errors by updating the status to "failed"
// if (isset($import_datasource)) {
// $import_datasource->update([
// 'status' => 'failed',
// 'response_body' => 'Error: ' . $e->getMessage(),
// 'finish_time' => now()
// ]);
// }
// }
// }
}

View File

@@ -0,0 +1,25 @@
<?php
namespace App\Enums;
enum PbgTaskApplicationTypes: string
{
case PERSETUJUAN_BG = '1';
case PERUBAHAN_BG = '2';
case SLF_BB = '4';
case SLF = '5';
public static function labels(): array
{
return [
null => "Pilih Application Type",
self::PERSETUJUAN_BG->value => 'Persetujuan Bangunan Gedung',
self::PERUBAHAN_BG->value => 'Perubahan Bangunan Gedung',
self::SLF_BB->value => 'Sertifikat Laik Fungsi - Bangunan Baru',
self::SLF->value => 'Sertifikat Laik Fungsi',
];
}
public static function getLabel(?string $status): ?string
{
return self::labels()[$status] ?? null;
}
}

View File

@@ -0,0 +1,22 @@
<?php
namespace App\Enums;
enum PbgTaskFilterData : string
{
case non_business = 'non-business';
case business = 'business';
case verified = 'verified';
case non_verified = 'non-verified';
case all = 'all';
public static function getAllOptions() : array {
return [
self::all->value => 'Potensi Berkas',
self::business->value => 'Usaha',
self::non_business->value => 'Bukan Usaha',
self::verified->value => 'Terverifikasi',
self::non_verified->value => 'Belum Terverifikasi',
];
}
}

View File

@@ -0,0 +1,59 @@
<?php
namespace App\Enums;
enum PbgTaskStatus: int
{
case VERIFIKASI_KELENGKAPAN = 1;
case PERBAIKAN_DOKUMEN = 2;
case PERMOHONAN_DIBATALKAN = 3;
case MENUNGGU_PENUGASAN_TPT_TPA = 4;
case MENUNGGU_JADWAL_KONSULTASI = 5;
case PELAKSANAAN_KONSULTASI = 6;
case PERBAIKAN_DOKUMEN_KONSULTASI = 8;
case PERMOHONAN_DITOLAK = 9;
case PERHITUNGAN_RETRIBUSI = 10;
case MENUNGGU_PEMBAYARAN_RETRIBUSI = 14;
case VERIFIKASI_PEMBAYARAN_RETRIBUSI = 15;
case RETRIBUSI_TIDAK_SESUAI = 16;
case VERIFIKASI_SK_PBG = 18;
case PENERBITAN_SK_PBG = 19;
case SK_PBG_TERBIT = 20;
case PENERBITAN_SPPST = 24;
case PROSES_PENERBITAN_SKRD = 25;
case MENUNGGU_PENUGASAN_TPT = 26;
case VERIFIKASI_DATA_TPT = 27;
case SERTIFIKAT_SLF_TERBIT = 28;
public static function getStatuses(): array
{
return [
null => "Pilih Status",
self::VERIFIKASI_KELENGKAPAN->value => "Verifikasi Kelengkapan Dokumen",
self::PERBAIKAN_DOKUMEN->value => "Perbaikan Dokumen",
self::PERMOHONAN_DIBATALKAN->value => "Permohonan Dibatalkan",
self::MENUNGGU_PENUGASAN_TPT_TPA->value => "Menunggu Penugasan TPT/TPA",
self::MENUNGGU_JADWAL_KONSULTASI->value => "Menunggu Jadwal Konsultasi",
self::PELAKSANAAN_KONSULTASI->value => "Pelaksanaan Konsultasi",
self::PERBAIKAN_DOKUMEN_KONSULTASI->value => "Perbaikan Dokumen Konsultasi",
self::PERMOHONAN_DITOLAK->value => "Permohonan Ditolak",
self::PERHITUNGAN_RETRIBUSI->value => "Perhitungan Retribusi",
self::MENUNGGU_PEMBAYARAN_RETRIBUSI->value => "Menunggu Pembayaran Retribusi",
self::VERIFIKASI_PEMBAYARAN_RETRIBUSI->value => "Verifikasi Pembayaran Retribusi",
self::RETRIBUSI_TIDAK_SESUAI->value => "Retribusi Tidak Sesuai",
self::VERIFIKASI_SK_PBG->value => "Verifikasi SK PBG",
self::PENERBITAN_SK_PBG->value => "Penerbitan SK PBG",
self::SK_PBG_TERBIT->value => "SK PBG Terbit",
self::PENERBITAN_SPPST->value => "Penerbitan SPPST",
self::PROSES_PENERBITAN_SKRD->value => "Proses Penerbitan SKRD",
self::MENUNGGU_PENUGASAN_TPT->value => "Menunggu Penugasan TPT",
self::VERIFIKASI_DATA_TPT->value => "Verifikasi Data TPT",
self::SERTIFIKAT_SLF_TERBIT->value => "Sertifikat SLF Terbit",
];
}
public static function getLabel(?int $status): ?string
{
return self::getStatuses()[$status] ?? null;
}
}

View File

@@ -0,0 +1,31 @@
<?php
namespace App\Exports;
use App\Models\PbgTaskGoogleSheet;
use Illuminate\Support\Facades\DB;
use Maatwebsite\Excel\Concerns\FromCollection;
use Maatwebsite\Excel\Concerns\WithHeadings;
class DistrictPaymentRecapExport implements FromCollection, WithHeadings
{
/**
* @return \Illuminate\Support\Collection
*/
public function collection()
{
return PbgTaskGoogleSheet::select(
'kecamatan',
DB::raw('SUM(nilai_retribusi_keseluruhan_simbg) as total')
)
->groupBy('kecamatan')->get();
}
public function headings(): array{
return [
'Kecamatan',
'Total'
];
}
}

View File

@@ -0,0 +1,90 @@
<?php
namespace App\Exports;
use App\Models\BigdataResume;
use Maatwebsite\Excel\Concerns\FromCollection;
use Maatwebsite\Excel\Concerns\WithHeadings;
use Maatwebsite\Excel\Concerns\WithMapping;
class ReportDirectorExport implements FromCollection, WithHeadings, WithMapping
{
/**
* @return \Illuminate\Support\Collection
*/
public function collection()
{
return BigdataResume::select(
'potention_count',
'potention_sum',
'non_verified_count',
'non_verified_sum',
'verified_count',
'verified_sum',
'business_count',
'business_sum',
'non_business_count',
'non_business_sum',
'spatial_count',
'spatial_sum',
'waiting_click_dpmptsp_count',
'waiting_click_dpmptsp_sum',
'issuance_realization_pbg_count',
'issuance_realization_pbg_sum',
'process_in_technical_office_count',
'process_in_technical_office_sum',
'year',
'created_at'
)->orderBy('id', 'desc')->get();
}
public function headings(): array{
return [
"Jumlah Potensi" ,
"Total Potensi" ,
"Jumlah Berkas Belum Terverifikasi" ,
"Total Berkas Belum Terverifikasi" ,
"Jumlah Berkas Terverifikasi" ,
"Total Berkas Terverifikasi" ,
"Jumlah Usaha" ,
"Total Usaha" ,
"Jumlah Non Usaha" ,
"Total Non Usaha" ,
"Jumlah Tata Ruang" ,
"Total Tata Ruang" ,
"Jumlah Menunggu Klik DPMPTSP" ,
"Total Menunggu Klik DPMPTSP" ,
"Jumlah Realisasi Terbit PBG" ,
"Total Realisasi Terbit PBG" ,
"Jumlah Proses Dinas Teknis" ,
"Total Proses Dinas Teknis",
"Tahun",
"Created"
];
}
public function map($row): array
{
return [
$row->potention_count,
$row->potention_sum,
$row->non_verified_count,
$row->non_verified_sum,
$row->verified_count,
$row->verified_sum,
$row->business_count,
$row->business_sum,
$row->non_business_count,
$row->non_business_sum,
$row->spatial_count,
$row->spatial_sum,
$row->waiting_click_dpmptsp_count,
$row->waiting_click_dpmptsp_sum,
$row->issuance_realization_pbg_count,
$row->issuance_realization_pbg_sum,
$row->process_in_technical_office_count,
$row->process_in_technical_office_sum,
$row->year,
$row->created_at ? $row->created_at->format('Y-m-d H:i:s') : null, // Format created_at as Y-m-d
];
}
}

View File

@@ -0,0 +1,71 @@
<?php
namespace App\Exports;
use App\Models\BigdataResume;
use Maatwebsite\Excel\Concerns\FromCollection;
use Maatwebsite\Excel\Concerns\WithHeadings;
class ReportPaymentRecapExport implements FromCollection, WithHeadings
{
/**
* @return \Illuminate\Support\Collection
*/
protected $startDate;
protected $endDate;
public function __construct($startDate, $endDate){
$this->startDate = $startDate;
$this->endDate = $endDate;
}
public function collection()
{
$query = BigdataResume::query()->orderBy('id', 'desc');
if ($this->startDate && $this->endDate) {
$query->whereBetween('created_at', [$this->startDate, $this->endDate]);
}
$items = $query->get();
$categoryMap = [
'potention_sum' => 'Potensi',
'non_verified_sum' => 'Belum Terverifikasi',
'verified_sum' => 'Terverifikasi',
'business_sum' => 'Usaha',
'non_business_sum' => 'Non Usaha',
'spatial_sum' => 'Tata Ruang',
'waiting_click_dpmptsp_sum' => 'Menunggu Klik DPMPTSP',
'issuance_realization_pbg_sum' => 'Realisasi Terbit PBG',
'process_in_technical_office_sum' => 'Proses Di Dinas Teknis',
];
// Restructure response
$data = [];
foreach ($items as $item) {
$createdAt = $item->created_at;
$id = $item->id;
foreach ($item->toArray() as $key => $value) {
// Only include columns with "sum" in their names
if (strpos($key, 'sum') !== false) {
$data[] = [
'category' => $categoryMap[$key] ?? $key, // Map category
'nominal' => number_format($value, 0, ',', '.'), // Format number
'created_at' => $createdAt->format('Y-m-d H:i:s'), // Format date
];
}
}
}
return collect($data);
}
public function headings(): array{
return [
'Kategori',
'Nominal',
'Created'
];
}
}

View File

@@ -0,0 +1,32 @@
<?php
namespace App\Exports;
use App\Models\PbgTask;
use Illuminate\Support\Facades\DB;
use Maatwebsite\Excel\Concerns\FromCollection;
use Maatwebsite\Excel\Concerns\WithHeadings;
class ReportPbgPtspExport implements FromCollection, WithHeadings
{
/**
* @return \Illuminate\Support\Collection
*/
public function collection()
{
return PbgTask::select(
'status_name',
DB::raw('COUNT(*) as total')
)
->groupBy('status', 'status_name')
->get();
}
public function headings(): array
{
return [
'Status Name',
'Total'
];
}
}

View File

@@ -0,0 +1,25 @@
<?php
namespace App\Exports;
use App\Models\TourismBasedKBLI;
use Maatwebsite\Excel\Concerns\FromCollection;
use Maatwebsite\Excel\Concerns\WithHeadings;
class ReportTourismExport implements FromCollection, WithHeadings
{
/**
* @return \Illuminate\Support\Collection
*/
public function collection()
{
return TourismBasedKBLI::select('kbli_title', 'total_records')->get();
}
public function headings(): array{
return [
'Jenis Bisnis Pariwisata',
'Jumlah Total'
];
}
}

View File

@@ -2,12 +2,17 @@
namespace App\Http\Controllers\Api;
use App\Exports\ReportDirectorExport;
use App\Exports\ReportPaymentRecapExport;
use App\Http\Controllers\Controller;
use App\Http\Resources\BigdataResumeResource;
use App\Models\BigdataResume;
use App\Models\DataSetting;
use Barryvdh\DomPDF\Facade\Pdf;
use Carbon\Carbon;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Log;
use Maatwebsite\Excel\Facades\Excel;
class BigDataResumeController extends Controller
{
@@ -162,7 +167,7 @@ class BigDataResumeController extends Controller
$query = BigdataResume::query()->orderBy('id', 'desc');
if($request->filled('search')){
$query->where('name', 'LIKE', '%'.$request->input('search').'%');
$query->where('year', 'LIKE', '%'.$request->input('search').'%');
}
$query = $query->paginate(config('app.paginate_per_page', 50));
@@ -173,6 +178,148 @@ class BigDataResumeController extends Controller
}
}
public function payment_recaps(Request $request)
{
try {
$query = BigdataResume::query()->orderBy('id', 'desc');
if ($request->filled('start_date') && $request->filled('end_date')) {
$startDate = Carbon::parse($request->input('start_date'))->startOfDay();
$endDate = Carbon::parse($request->input('end_date'))->endOfDay();
$query->whereBetween('created_at', [$startDate, $endDate]);
}
$data = $query->paginate(50);
// Restructure response
$transformedData = [];
foreach ($data as $item) {
$createdAt = $item->created_at;
$id = $item->id;
foreach ($item->toArray() as $key => $value) {
// Only include columns with "sum" in their names
if (strpos($key, 'sum') !== false) {
$transformedData[] = [
'id' => $id,
'category' => $key,
'nominal' => $value,
'created_at' => $createdAt,
];
}
}
}
return response()->json([
'data' => $transformedData, // Flat array
'pagination' => [
'total' => count($transformedData),
'per_page' => $data->perPage(),
'current_page' => $data->currentPage(),
'last_page' => $data->lastPage(),
]
]);
} catch (\Exception $e) {
Log::error($e->getMessage());
return response()->json(['message' => 'Error when fetching data'], 500);
}
}
public function export_excel_payment_recaps(Request $request)
{
$startDate = null;
$endDate = null;
if ($request->filled('start_date') && $request->filled('end_date')) {
$startDate = Carbon::parse($request->input('start_date'))->startOfDay();
$endDate = Carbon::parse($request->input('end_date'))->endOfDay();
}
return Excel::download(new ReportPaymentRecapExport($startDate, $endDate), 'laporan-rekap-pembayaran.xlsx');
}
public function export_pdf_payment_recaps(Request $request){
$query = BigdataResume::query()->orderBy('id', 'desc');
if ($request->filled('start_date') && $request->filled('end_date')) {
$startDate = Carbon::parse($request->input('start_date'))->startOfDay();
$endDate = Carbon::parse($request->input('end_date'))->endOfDay();
$query->whereBetween('created_at', [$startDate, $endDate]);
}
$items = $query->get();
// Define category mapping
$categoryMap = [
'potention_sum' => 'Potensi',
'non_verified_sum' => 'Belum Terverifikasi',
'verified_sum' => 'Terverifikasi',
'business_sum' => 'Usaha',
'non_business_sum' => 'Non Usaha',
'spatial_sum' => 'Tata Ruang',
'waiting_click_dpmptsp_sum' => 'Menunggu Klik DPMPTSP',
'issuance_realization_pbg_sum' => 'Realisasi Terbit PBG',
'process_in_technical_office_sum' => 'Proses Di Dinas Teknis',
];
// Restructure response
$data = [];
foreach ($items as $item) {
$createdAt = $item->created_at;
$id = $item->id;
foreach ($item->toArray() as $key => $value) {
// Only include columns with "sum" in their names
if (strpos($key, 'sum') !== false) {
$data[] = [
'id' => $id,
'category' => $categoryMap[$key] ?? $key, // Map category
'nominal' => $value, // Format number
'created_at' => $createdAt->format('Y-m-d H:i:s'), // Format date
];
}
}
}
$pdf = Pdf::loadView('exports.payment_recaps_report', compact('data'));
return $pdf->download('laporan-rekap-pembayaran.pdf');
}
public function export_excel_report_director(){
return Excel::download(new ReportDirectorExport, 'laporan-pimpinan.xlsx');
}
public function export_pdf_report_director(){
$data = BigdataResume::select(
'potention_count',
'potention_sum',
'non_verified_count',
'non_verified_sum',
'verified_count',
'verified_sum',
'business_count',
'business_sum',
'non_business_count',
'non_business_sum',
'spatial_count',
'spatial_sum',
'waiting_click_dpmptsp_count',
'waiting_click_dpmptsp_sum',
'issuance_realization_pbg_count',
'issuance_realization_pbg_sum',
'process_in_technical_office_count',
'process_in_technical_office_sum',
'year',
'created_at'
)->orderBy('id', 'desc')->get();
$pdf = Pdf::loadView('exports.director_report', compact('data'))->setPaper('a4', 'landscape');
return $pdf->download('laporan-pimpinan.pdf');
}
private function response_empty_resume(){
$result = [
'target_pad' => [

View File

@@ -34,7 +34,7 @@ class ChatbotController extends Controller
};
$chatHistory = $request->input('chatHistory');
// Log::info('Chat history sebelum disimpan:', ['history' => $chatHistory]);
Log::info('Chat history sebelum disimpan:', ['history' => $chatHistory]);
if ($main_content === "UNKNOWN") {
return response()->json(['response' => 'Invalid tab_active value.'], 400);
@@ -43,15 +43,16 @@ class ChatbotController extends Controller
// info($main_content);
$queryResponse = $this->openAIService->generateQueryBasedMainContent($request->input('prompt'), $main_content, $chatHistory);
$firstValidation = $this->openAIService->validateSyntaxQuery($queryResponse);
$secondValidation = $this->openAIService->validateSyntaxQuery($queryResponse);
if (str_contains($queryResponse, 'tidak relevan') || str_contains($queryResponse, 'tidak valid') || str_starts_with($queryResponse, 'Prompt')) {
return response()->json(['response' => $queryResponse], 400);
}
$formattedResultQuery = "[]";
$queryResponse = str_replace(['```sql', '```'], '', $queryResponse);
$resultQuery = DB::select($queryResponse);
$formattedResultQuery = json_encode($resultQuery, JSON_PRETTY_PRINT);
// info($formattedResultQuery);
info($formattedResultQuery);
$nlpResult = $this->openAIService->generateNLPFromQuery($request->input('prompt'), $formattedResultQuery);
$finalGeneratedText =$this->openAIService->generateFinalText($nlpResult);
@@ -92,9 +93,6 @@ class ChatbotController extends Controller
$queryResponse = $this->openAIService->createMainQuery($classifyResponse, $request->input('prompt'), $chatHistory);
info($queryResponse);
$firstValidation = $this->openAIService->validateSyntaxQuery($queryResponse);
$secondValidation = $this->openAIService->validateSyntaxQuery($queryResponse);
$formattedResultQuery = "[]";
$queryResponse = str_replace(['```sql', '```'], '', $queryResponse);

View File

@@ -34,7 +34,7 @@ class GlobalSettingsController extends Controller
try {
$data = GlobalSetting::create($request->validated());
return new GlobalSettingResource($data);
} catch (\Exception $e) {
} catch (Exception $e) {
return $this->resError($e->getMessage(), null, $e->getCode());
}
}

View File

@@ -3,33 +3,15 @@
namespace App\Http\Controllers\Api;
use App\Http\Controllers\Controller;
use App\Services\GoogleSheetService;
use Illuminate\Http\Request;
class GoogleSheetController extends Controller
{
protected $googleSheetService;
public function __construct(GoogleSheetService $googleSheetService){
$this->googleSheetService = $googleSheetService;
}
/**
* Display a listing of the resource.
*/
public function index()
public function index(Request $request)
{
$dataCollection = $this->googleSheetService->getSheetDataCollection();
$result = [
"last_row" => $this->googleSheetService->getLastRowByColumn("C"),
"last_column" => $this->googleSheetService->getLastColumn(),
"header" => $this->googleSheetService->getHeader(),
"data_collection" => $dataCollection
];
return response()->json($result);
}
/**
* Store a newly created resource in storage.
*/
public function store(Request $request)
{
//

View File

@@ -0,0 +1,85 @@
<?php
namespace App\Http\Controllers\Api;
use App\Http\Controllers\Controller;
use App\Models\BigdataResume;
use Carbon\Carbon;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\DB;
class GrowthReportAPIController extends Controller
{
/**
* Display a listing of the resource.
*/
public function index(Request $request)
{
// Get current date
$today = Carbon::today();
// Define default range: 1 month back from today
$defaultStart = $today->copy()->subMonth();
$defaultEnd = $today;
// Use request values if provided, else use defaults
$startDate = $request->input('start_date', $defaultStart->toDateString());
$endDate = $request->input('end_date', $defaultEnd->toDateString());
// Optional year filter (used if specified)
$year = $request->input('year', now()->year);
$query = BigdataResume::selectRaw("
DATE(created_at) as date,
SUM(potention_sum) as potention_sum,
SUM(verified_sum) as verified_sum,
SUM(non_verified_sum) as non_verified_sum
")
->whereBetween('created_at', [$startDate, $endDate]);
$query->whereNotNull('year')
->where('year', '!=', 'all');
$data = $query->groupBy(DB::raw('DATE(created_at)'))
->orderBy(DB::raw('DATE(created_at)'))
->get()
->map(function ($item) {
$item->date = Carbon::parse($item->date)->format('d M Y');
return $item;
});
return response()->json($data);
}
/**
* Store a newly created resource in storage.
*/
public function store(Request $request)
{
//
}
/**
* Display the specified resource.
*/
public function show(string $id)
{
//
}
/**
* Update the specified resource in storage.
*/
public function update(Request $request, string $id)
{
//
}
/**
* Remove the specified resource from storage.
*/
public function destroy(string $id)
{
//
}
}

View File

@@ -22,7 +22,8 @@ class MenusController extends Controller
$query = $query->where("name", "like", "%".$request->get("search")."%");
}
return response()->json($query->paginate(config('app.paginate_per_page', 50)));
// return response()->json($query->paginate(config('app.paginate_per_page', 50)));
return MenuResource::collection($query->paginate(config('app.paginate_per_page',50)));
}
/**

View File

@@ -0,0 +1,109 @@
<?php
namespace App\Http\Controllers\Api;
use App\Http\Controllers\Controller;
use App\Models\PbgTaskAttachment;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Storage;
use Symfony\Component\HttpFoundation\Response;
class PbgTaskAttachmentsController extends Controller
{
/**
* Display a listing of the resource.
*/
public function index()
{
//
}
/**
* Store a newly created resource in storage.
*/
public function store(Request $request, $pbg_task_id)
{
try{
$request->validate([
'file' => 'required|file|mimes:jpg,png,pdf|max:5120',
'pbg_type' => 'string'
]);
$attachment = PbgTaskAttachment::create([
'pbg_task_id' => $pbg_task_id,
'file_name' => $request->file('file')->getClientOriginalName(),
'file_path' => '', // empty path initially
'pbg_type' => $request->pbg_type == 'bukti_bayar' ? 'bukti_bayar' : 'berita_acara'
]);
$file = $request->file('file');
$path = $file->store("uploads/pbg-tasks/{$pbg_task_id}/{$attachment->id}", "public");
$attachment->update([
'file_path' => $path,
]);
return response()->json([
'message' => 'File uploaded successfully.',
'attachment' => [
'id' => $attachment->id,
'file_name' => $attachment->file_name,
'file_url' => Storage::url($attachment->file_path),
'pbg_type' => $attachment->pbg_type
]
]);
}catch(\Exception $e){
\Log::error($e->getMessage());
return response()->json([
"success" => false,
"message" => $e->getTraceAsString()
]);
}
}
/**
* Display the specified resource.
*/
public function show(string $id)
{
//
}
/**
* Update the specified resource in storage.
*/
public function update(Request $request, string $id)
{
//
}
/**
* Remove the specified resource from storage.
*/
public function destroy(string $id)
{
//
}
public function download(string $id)
{
try {
$data = PbgTaskAttachment::findOrFail($id);
$filePath = $data->file_path; // already relative to 'public' disk
if (!Storage::disk('public')->exists($filePath)) {
return response()->json([
"success" => false,
"message" => "File not found on server"
], Response::HTTP_NOT_FOUND);
}
return Storage::disk('public')->download($filePath, $data->file_name);
} catch (\Exception $e) {
return response()->json([
"success" => false,
"message" => $e->getMessage()
]);
}
}
}

View File

@@ -3,6 +3,8 @@
namespace App\Http\Controllers\Api;
use App\Enums\ImportDatasourceStatus;
use App\Enums\PbgTaskApplicationTypes;
use App\Enums\PbgTaskStatus;
use App\Http\Controllers\Controller;
use App\Http\Requests\PbgTaskMultiStepRequest;
use App\Http\Resources\PbgTaskResource;
@@ -14,6 +16,7 @@ use App\Services\GoogleSheetService;
use Carbon\Carbon;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\DB;
use Illuminate\Validation\Rules\Enum;
class PbgTaskController extends Controller
{
@@ -116,9 +119,63 @@ class PbgTaskController extends Controller
/**
* Update the specified resource in storage.
*/
public function update(Request $request, string $id)
public function update(Request $request, string $task_uuid)
{
//
try{
$pbg_task = PbgTask::where('uuid',$task_uuid)->first();
if(!$pbg_task){
return response()->json([
"success"=> false,
"message"=> "Data PBG Task tidak ditemukan",
], 404);
}
$validated = $request->validate([
'name' => 'required|string|max:255',
'owner_name' => 'required|string|max:255',
'application_type' => ['nullable', new Enum(PbgTaskApplicationTypes::class)],
'condition' => 'required|string|max:255',
'registration_number' => 'required|string|max:255',
'document_number' => 'required|string|max:255',
'status' => ['nullable', new Enum(PbgTaskStatus::class)],
'address' => 'required|string|max:255',
'slf_status_name' => 'nullable|string|max:255',
'function_type' => 'required|string|max:255',
'consultation_type' => 'required|string|max:255',
'due_date' => 'nullable|date|after_or_equal:today',
]);
$statusLabel = $validated['status'] !== null ? PbgTaskStatus::getLabel($validated['status']) : null;
$applicationLabel = $validated['application_type'] !== null ? PbgTaskApplicationTypes::getLabel($validated['application_type']) : null;
$pbg_task->update([
'name' => $validated['name'],
'owner_name' => $validated['owner_name'],
'application_type' => $validated['application_type'],
'application_type_name' => $applicationLabel, // Automatically set application_type_name
'condition' => $validated['condition'],
'registration_number' => $validated['registration_number'],
'document_number' => $validated['document_number'],
'status' => $validated['status'],
'status_name' => $statusLabel, // Automatically set status_name
'address' => $validated['address'],
'slf_status_name' => $validated['slf_status_name'],
'function_type' => $validated['function_type'],
'consultation_type' => $validated['consultation_type'],
'due_date' => $validated['due_date'],
]);
return response()->json([
"success"=> true,
"message"=> "Data berhasil diubah",
"data"=> $pbg_task
]);
}catch(\Exception $e){
return response()->json([
"success"=> false,
"message"=> $e->getMessage(),
]);
}
}
/**
@@ -135,255 +192,4 @@ class PbgTaskController extends Controller
]);
}
public function syncPbgFromGoogleSheet(){
$import_datasource = ImportDatasource::create([
"message" => "initialization",
"response_body" => null,
"status" => ImportDatasourceStatus::Processing->value,
]);
try{
$totalRowCount = $this->googleSheetService->getLastRowByColumn("C");
$sheetData = $this->googleSheetService->getSheetDataCollection($totalRowCount);
$sheet_big_data = $this->googleSheetService->get_data_by_sheet();
$data_setting_result = []; // Initialize result storage
$found_section = null; // Track which section is found
foreach ($sheet_big_data as $row) {
// Check for section headers
if (in_array("•PROSES PENERBITAN:", $row)) {
$found_section = "MENUNGGU_KLIK_DPMPTSP";
} elseif (in_array("•BERKAS AKTUAL TERVERIFIKASI DINAS TEKNIS 2024:", $row)) {
$found_section = "REALISASI_TERBIT_PBG";
} elseif (in_array("•TERPROSES DI DPUTR: belum selesai rekomtek'", $row)) {
$found_section = "PROSES_DINAS_TEKNIS";
}
// If a section is found and we reach "Grand Total", save the corresponding values
if ($found_section && isset($row[0]) && trim($row[0]) === "Grand Total") {
if ($found_section === "MENUNGGU_KLIK_DPMPTSP") {
$data_setting_result["MENUNGGU_KLIK_DPMPTSP_COUNT"] = $row[2] ?? null;
$data_setting_result["MENUNGGU_KLIK_DPMPTSP_SUM"] = $row[3] ?? null;
} elseif ($found_section === "REALISASI_TERBIT_PBG") {
$data_setting_result["REALISASI_TERBIT_PBG_COUNT"] = $row[2] ?? null;
$data_setting_result["REALISASI_TERBIT_PBG_SUM"] = $row[4] ?? null;
} elseif ($found_section === "PROSES_DINAS_TEKNIS") {
$data_setting_result["PROSES_DINAS_TEKNIS_COUNT"] = $row[2] ?? null;
$data_setting_result["PROSES_DINAS_TEKNIS_SUM"] = $row[3] ?? null;
}
// Reset section tracking after capturing "Grand Total"
$found_section = null;
}
}
foreach ($data_setting_result as $key => $value) {
DataSetting::updateOrInsert(
["key" => $key], // Find by key
["value" => $value] // Update or insert value
);
}
$mapToUpsert = [];
$count = 0;
foreach($sheetData as $data){
$mapToUpsert[] =
[
'no_registrasi' => $data['no__registrasi'] ?? null,
'jenis_konsultasi' => $data['jenis_konsultasi'] ?? null,
'fungsi_bg' => $data['fungsi_bg'] ?? null,
'tgl_permohonan' => $this->convertToDate($data['tgl_permohonan']),
'status_verifikasi' => $data['status_verifikasi'] ?? null,
'status_permohonan' => $this->convertToDate($data['status_permohonan']),
'alamat_pemilik' => $data['alamat_pemilik'] ?? null,
'no_hp' => $data['no__hp'] ?? null,
'email' => $data['e_mail'] ?? null,
'tanggal_catatan' => $this->convertToDate($data['tanggal_catatan']),
'catatan_kekurangan_dokumen' => $data['catatan_kekurangan_dokumen'] ?? null,
'gambar' => $data['gambar'] ?? null,
'krk_kkpr' => $data['krk_kkpr'] ?? null,
'no_krk' => $data['no__krk'] ?? null,
'lh' => $data['lh'] ?? null,
'ska' => $data['ska'] ?? null,
'keterangan' => $data['keterangan'] ?? null,
'helpdesk' => $data['helpdesk'] ?? null,
'pj' => $data['pj'] ?? null,
'kepemilikan' => $data['kepemilikan'] ?? null,
'potensi_taru' => $data['potensi_taru'] ?? null,
'validasi_dinas' => $data['validasi_dinas'] ?? null,
'kategori_retribusi' => $data['kategori_retribusi'] ?? null,
'no_urut_ba_tpt' => $data['no__urut_ba_tpt__2024_0001_'] ?? null,
'tanggal_ba_tpt' => $this->convertToDate($data['tanggal_ba_tpt']),
'no_urut_ba_tpa' => $data['no__urut_ba_tpa'] ?? null,
'tanggal_ba_tpa' => $this->convertToDate($data['tanggal_ba_tpa']),
'no_urut_skrd' => $data['no__urut_skrd__2024_0001_'] ?? null,
'tanggal_skrd' => $this->convertToDate($data['tanggal_skrd']),
'ptsp' => $data['ptsp'] ?? null,
'selesai_terbit' => $data['selesai_terbit'] ?? null,
'tanggal_pembayaran' => $this->convertToDate($data['tanggal_pembayaran__yyyy_mm_dd_']),
'format_sts' => $data['format_sts'] ?? null,
'tahun_terbit' => (int) $data['tahun_terbit'] ?? null,
'tahun_berjalan' => (int) $data['tahun_berjalan'] ?? null,
'kelurahan' => $data['kelurahan'] ?? null,
'kecamatan' => $data['kecamatan'] ?? null,
'lb' => $this->convertToDecimal($data['lb']) ?? null,
'tb' => $this->convertToDecimal($data['tb']) ?? null,
'jlb' => (int) $data['jlb'] ?? null,
'unit' => (int) $data['unit'] ?? null,
'usulan_retribusi' => (int) $data['usulan_retribusi'] ?? null,
'nilai_retribusi_keseluruhan_simbg' => $this->convertToDecimal($data['nilai_retribusi_keseluruhan__simbg_']) ?? null,
'nilai_retribusi_keseluruhan_pad' => $this->convertToDecimal($data['nilai_retribusi_keseluruhan__pad_']) ?? null,
'denda' => $this->convertToDecimal($data['denda']) ?? null,
'latitude' => $data['latitude'] ?? null,
'longitude' => $data['longitude'] ?? null,
'nik_nib' => $data['nik_nib'] ?? null,
'dok_tanah' => $data['dok__tanah'] ?? null,
'temuan' => $data['temuan'] ?? null,
];
}
DB::beginTransaction();
$batchSize = 1000;
$chunks = array_chunk($mapToUpsert, $batchSize);
foreach($chunks as $chunk){
PbgTaskGoogleSheet::upsert($chunk, ["no_registrasi"],[
'jenis_konsultasi',
'nama_pemilik',
'lokasi_bg',
'fungsi_bg',
'nama_bangunan',
'tgl_permohonan',
'status_verifikasi',
'status_permohonan',
'alamat_pemilik',
'no_hp',
'email',
'tanggal_catatan',
'catatan_kekurangan_dokumen',
'gambar',
'krk_kkpr',
'no_krk',
'lh',
'ska',
'keterangan',
'helpdesk',
'pj',
'kepemilikan',
'potensi_taru',
'validasi_dinas',
'kategori_retribusi',
'no_urut_ba_tpt',
'tanggal_ba_tpt',
'no_urut_ba_tpa',
'tanggal_ba_tpa',
'no_urut_skrd',
'tanggal_skrd',
'ptsp',
'selesai_terbit',
'tanggal_pembayaran',
'format_sts',
'tahun_terbit',
'tahun_berjalan',
'kelurahan',
'kecamatan',
'lb',
'tb',
'jlb',
'unit',
'usulan_retribusi',
'nilai_retribusi_keseluruhan_simbg',
'nilai_retribusi_keseluruhan_pad',
'denda',
'latitude',
'longitude',
'nik_nib',
'dok_tanah',
'temuan',
]);
}
$total_data = count($mapToUpsert);
$import_datasource->update([
"message" => "Successfully processed: {$total_data}",
"status" => ImportDatasourceStatus::Success->value,
]);
DB::commit();
return response()->json([
"success" => true,
"message" => "Data berhasil disimpan ke database"
], 200);
}catch(\Exception $ex){
DB::rollBack();
$import_datasource->update([
"message" => "Failed to importing",
"response_body" => $ex->getMessage(),
"status" => ImportDatasourceStatus::Failed->value,
]);
return response()->json([
"success" => false,
"message" => "Gagal menyimpan data",
"error" => $ex->getMessage()
], 500);
}
}
protected function convertToDecimal(?string $value): ?float
{
if (empty($value)) {
return null; // Return null if the input is empty
}
// Remove all non-numeric characters except comma and dot
$value = preg_replace('/[^0-9,\.]/', '', $value);
// If the number contains both dot (.) and comma (,)
if (strpos($value, '.') !== false && strpos($value, ',') !== false) {
$value = str_replace('.', '', $value); // Remove thousands separator
$value = str_replace(',', '.', $value); // Convert decimal separator to dot
}
// If only a dot is present (assumed as thousands separator)
elseif (strpos($value, '.') !== false) {
$value = str_replace('.', '', $value); // Remove all dots (treat as thousands separators)
}
// If only a comma is present (assumed as decimal separator)
elseif (strpos($value, ',') !== false) {
$value = str_replace(',', '.', $value); // Convert comma to dot (decimal separator)
}
// Ensure the value is numeric before returning
return is_numeric($value) ? (float) number_format((float) $value, 2, '.', '') : null;
}
protected function convertToInteger($value) {
// Check if the value is an empty string, and return null if true
if (trim($value) === "") {
return null;
}
// Otherwise, cast to integer
return (int) $value;
}
protected function convertToDate($dateString)
{
try {
// Check if the string is empty
if (empty($dateString)) {
return null;
}
// Try to parse the date string
$date = Carbon::parse($dateString);
// Return the Carbon instance
return $date->format('Y-m-d');
} catch (\Exception $e) {
// Return null if an error occurs during parsing
return null;
}
}
}

View File

@@ -0,0 +1,61 @@
<?php
namespace App\Http\Controllers\Api;
use App\Http\Controllers\Controller;
use App\Http\Resources\PbgTaskGoogleSheetResource;
use App\Models\PbgTaskGoogleSheet;
use Illuminate\Http\Request;
class PbgTaskGoogleSheetsController extends Controller
{
/**
* Display a listing of the resource.
*/
public function index(Request $request)
{
$query = PbgTaskGoogleSheet::query()->orderBy('id', 'desc');
if ($request->filled('search')) {
$query->where('no_registrasi', 'like', "%{$request->get('search')}%");
}
return PbgTaskGoogleSheetResource::collection($query->paginate(config('app.paginate_per_page', 50)));
}
/**
* Store a newly created resource in storage.
*/
public function store(Request $request)
{
//
}
/**
* Display the specified resource.
*/
public function show(string $id)
{
//
}
/**
* Update the specified resource in storage.
*/
public function update(Request $request, string $id)
{
//
}
/**
* Remove the specified resource from storage.
*/
public function destroy(string $id)
{
try{
$data = PbgTaskGoogleSheet::find($id);
$data->delete();
return response()->json(['message' => 'Data deleted successfully'], 200);
}catch(\Exception $e){
return response()->json(['message' => 'Failed to delete data'], 500);
}
}
}

View File

@@ -0,0 +1,29 @@
<?php
namespace App\Http\Controllers\Api;
use App\Exports\ReportPbgPtspExport;
use App\Http\Controllers\Controller;
use App\Models\PbgTask;
use Barryvdh\DomPDF\Facade\Pdf;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\DB;
use Maatwebsite\Excel\Facades\Excel;
class ReportPbgPtspController extends Controller
{
public function export_excel(){
return Excel::download(new ReportPbgPtspExport, 'laporan-ptsp.xlsx');
}
public function export_pdf(){
$data = PbgTask::select(
'status',
'status_name', // Keeping this column
DB::raw('COUNT(*) as total')
)
->groupBy('status', 'status_name')
->get();
$pdf = Pdf::loadView('exports.ptsp_report', compact('data'));
return $pdf->download('laporan-ptsp.pdf');
}
}

View File

@@ -0,0 +1,22 @@
<?php
namespace App\Http\Controllers\Api;
use App\Exports\ReportTourismExport;
use App\Http\Controllers\Controller;
use App\Models\TourismBasedKBLI;
use Barryvdh\DomPDF\Facade\Pdf;
use Illuminate\Http\Request;
use Maatwebsite\Excel\Facades\Excel;
class ReportTourismsController extends Controller
{
public function export_excel(){
return Excel::download(new ReportTourismExport, 'laporan-pariwisata.xlsx');
}
public function export_pdf(){
$data = TourismBasedKBLI::all();
$pdf = Pdf::loadView('exports.tourisms_report', compact('data'));
return $pdf->download('laporan-pariwisata.pdf');
}
}

View File

@@ -2,10 +2,17 @@
namespace App\Http\Controllers\Api;
use App\Exports\DistrictPaymentRecapExport;
use App\Http\Controllers\Controller;
use App\Http\Resources\RequestAssignmentResouce;
use App\Models\PbgTask;
use App\Models\PbgTaskGoogleSheet;
use Barryvdh\DomPDF\Facade\Pdf;
use Illuminate\Support\Facades\DB;
use Exception;
use Illuminate\Http\Request;
use Log;
use Maatwebsite\Excel\Facades\Excel;
class RequestAssignmentController extends Controller
{
@@ -14,15 +21,112 @@ class RequestAssignmentController extends Controller
*/
public function index(Request $request)
{
$query = PbgTask::query()->orderBy('id', 'desc');
if($request->has('search') && !empty($request->get("search"))){
$query->where('name', 'LIKE', '%'.$request->get('search').'%')
->orWhere('registration_number', 'LIKE', '%'.$request->get('search').'%')
->orWhere('document_number', 'LIKE', '%'.$request->get('search').'%');
$query = PbgTask::with([
'attachments' => function ($q) {
$q->whereIn('pbg_type', ['berita_acara', 'bukti_bayar']);
},
'googleSheet'
])->orderBy('id', 'desc');
if ($request->has('filter') && !empty($request->get('filter'))) {
$filter = strtolower($request->get('filter'));
switch ($filter) {
case 'non-business':
$query->whereRaw("LOWER(function_type) != ?", ['sebagai tempat usaha'])->orWhereNull('function_type');
break;
case 'business':
$query->whereRaw("LOWER(function_type) = ?", ['sebagai tempat usaha']);
break;
case 'verified':
$query->whereHas('googleSheet', function ($q) {
$q->whereRaw("LOWER(status_verifikasi) = ?", ['selesai verifikasi']);
});
break;
case 'non-verified':
$query->where(function ($q) {
$q->whereDoesntHave('googleSheet')
->orWhereHas('googleSheet', function ($q2) {
$q2->whereRaw("LOWER(status_verifikasi) != ?", ['selesai verifikasi'])->orWhereNull('status_verifikasi');
});
});
break;
}
}
if ($request->has('search') && !empty($request->get("search"))) {
$search = $request->get('search');
$query->where(function ($q) use ($search) {
$q->where('name', 'LIKE', "%$search%")
->orWhere('registration_number', 'LIKE', "%$search%")
->orWhere('document_number', 'LIKE', "%$search%");
});
}
return RequestAssignmentResouce::collection($query->paginate());
}
public function report_payment_recaps(Request $request)
{
try {
// Query dengan group by kecamatan dan sum nilai_retribusi_keseluruhan_simbg
$query = PbgTaskGoogleSheet::select(
'kecamatan',
DB::raw('SUM(nilai_retribusi_keseluruhan_simbg) as total')
)
->groupBy('kecamatan')
->paginate(10);
// Return hasil dalam JSON format
return response()->json([
'success' => true,
'data' => $query
]);
} catch (Exception $e) {
Log::error($e->getMessage());
return response()->json(['message' => 'Terjadi kesalahan: ' . $e->getMessage()], 500);
}
}
public function export_excel_district_payment_recaps(){
return Excel::download(new DistrictPaymentRecapExport, 'laporan-rekap-data-pembayaran.xlsx');
}
public function export_pdf_district_payment_recaps(){
$data = PbgTaskGoogleSheet::select(
'kecamatan',
DB::raw('SUM(nilai_retribusi_keseluruhan_simbg) as total')
)
->groupBy('kecamatan')->get();
$pdf = Pdf::loadView('exports.district_payment_report', compact('data'));
return $pdf->download('laporan-rekap-data-pembayaran.pdf');
}
public function report_pbg_ptsp()
{
try {
// Query dengan group by status dan count total per status
$query = PbgTask::select(
'status',
'status_name',
DB::raw('COUNT(*) as total')
)
->groupBy('status', 'status_name')
->paginate(10);
// Return hasil dalam JSON format
return response()->json([
'success' => true,
'data' => $query
]);
} catch (Exception $e) {
Log::error($e->getMessage());
return response()->json(['message' => 'Terjadi kesalahan: ' . $e->getMessage()], 500);
}
}
/**
* Store a newly created resource in storage.
*/

View File

@@ -4,9 +4,16 @@ namespace App\Http\Controllers\Api;
use App\Enums\ImportDatasourceStatus;
use App\Http\Controllers\Controller;
use App\Jobs\RetrySyncronizeJob;
use App\Jobs\ScrapingDataJob;
use App\Jobs\SyncronizeSIMBG;
use App\Models\ImportDatasource;
use App\Traits\GlobalApiResponse;
use App\Services\ServiceTokenSIMBG;
use GuzzleHttp\Client;
use App\Services\ServiceGoogleSheet;
use App\Services\ServicePbgTask;
use App\Services\ServiceTabPbgTask;
use Illuminate\Support\Facades\Artisan;
use Illuminate\Http\Request;
@@ -23,40 +30,33 @@ class ScrapingController extends Controller
return $this->resError("Failed to execute while processing another scraping");
}
// run service artisan command
SyncronizeSIMBG::dispatch();
// use ole schema synchronization
// dispatch(new SyncronizeSIMBG());
// use new schema synchronization
dispatch(new ScrapingDataJob());
return $this->resSuccess(["message" => "Success execute scraping service on background, check status for more"]);
}
/**
* Store a newly created resource in storage.
*/
public function store(Request $request)
{
//
}
public function retry_syncjob(string $import_datasource_id){
try{
/**
* Display the specified resource.
*/
public function show(string $id)
{
//
}
$import_datasource = ImportDatasource::find($import_datasource_id);
if(!$import_datasource){
return $this->resError("Invalid import datasource id", null, 404);
}
/**
* Update the specified resource in storage.
*/
public function update(Request $request, string $id)
{
//
}
/**
* Remove the specified resource from storage.
*/
public function destroy(string $id)
{
//
dispatch(new RetrySyncronizeJob($import_datasource->id));
return response()->json([
"success" => true,
"message" => "Retrying scrape job on background, check status for more"
]);
}catch(\Exception $e){
return response()->json([
"success" => false,
"message" => "Failed to retry sync job",
"error" => $e->getMessage()
]);
}
}
}

View File

@@ -0,0 +1,64 @@
<?php
namespace App\Http\Controllers\Api;
use App\Http\Controllers\Controller;
use App\Http\Resources\TaskAssignmentsResource;
use App\Models\TaskAssignment;
use Illuminate\Http\Request;
class TaskAssignmentsController extends Controller
{
/**
* Display a listing of the resource.
*/
public function index(Request $request, $uuid)
{
try{
$query = TaskAssignment::query()
->where('pbg_task_uid', $uuid)
->orderBy('id', 'desc');
if ($request->filled('search')) {
$query->where('name', 'like', "%{$request->get('search')}%")
->orWhere('email', 'like', "%{$request->get('search')}%");
}
return TaskAssignmentsResource::collection($query->paginate(config('app.paginate_per_page', 50)));
}catch(\Exception $exception){
return response()->json(['message' => $exception->getMessage()], 500);
}
}
/**
* Store a newly created resource in storage.
*/
public function store(Request $request)
{
//
}
/**
* Display the specified resource.
*/
public function show(string $id)
{
//
}
/**
* Update the specified resource in storage.
*/
public function update(Request $request, string $id)
{
//
}
/**
* Remove the specified resource from storage.
*/
public function destroy(string $id)
{
//
}
}

View File

@@ -30,7 +30,8 @@ class UsersController extends Controller
public function index(Request $request){
$query = User::query();
if($request->has('search') && !empty($request->get("search"))){
$query->where('name', 'LIKE', '%'.$request->get('search').'%');
$query->where('name', 'LIKE', '%'.$request->get('search').'%')
->orWhere('email', 'LIKE', '%'.$request->get('search').'%');
}
return UserResource::collection($query->paginate(config('app.paginate_per_page', 50)));
}
@@ -84,4 +85,17 @@ class UsersController extends Controller
return response()->json(['message' => $e->getMessage()],500);
}
}
public function destroy($id){
try{
$user = User::findOrFail($id);
DB::beginTransaction();
$user->delete();
DB::commit();
return response()->json(['message' => 'Successfully deleted'], 200);
}catch(\Exception $e){
Log::error('Failed to delete user: '. $e->getMessage());
return response()->json(['message' => 'Failed to delete user'],500);
}
}
}

View File

@@ -0,0 +1,65 @@
<?php
namespace App\Http\Controllers\Approval;
use App\Http\Controllers\Controller;
use Illuminate\Http\Request;
class ApprovalController extends Controller
{
/**
* Display a listing of the resource.
*/
public function index()
{
return view('approval.index');
}
/**
* Show the form for creating a new resource.
*/
public function create()
{
//
}
/**
* Store a newly created resource in storage.
*/
public function store(Request $request)
{
//
}
/**
* Display the specified resource.
*/
public function show(string $id)
{
//
}
/**
* Show the form for editing the specified resource.
*/
public function edit(string $id)
{
//
}
/**
* Update the specified resource in storage.
*/
public function update(Request $request, string $id)
{
//
}
/**
* Remove the specified resource from storage.
*/
public function destroy(string $id)
{
//
}
}

View File

@@ -14,74 +14,30 @@ class BusinessOrIndustriesController extends Controller
*/
public function index(Request $request)
{
$menuId = $request->query('menu_id');
$user = Auth::user();
$userId = $user->id;
// Ambil role_id yang dimiliki user
$roleIds = DB::table('user_role')
->where('user_id', $userId)
->pluck('role_id');
// Ambil data akses berdasarkan role_id dan menu_id
$roleAccess = DB::table('role_menu')
->whereIn('role_id', $roleIds)
->where('menu_id', $menuId)
->first();
// Pastikan roleAccess tidak null sebelum mengakses properti
$creator = $roleAccess->allow_create ?? 0;
$updater = $roleAccess->allow_update ?? 0;
$destroyer = $roleAccess->allow_destroy ?? 0;
return view('business-industries.index', compact('creator', 'updater', 'destroyer'));
$menuId = $request->query('menu_id') ?? $request->input('menu_id');
$permissions = $this->permissions[$menuId]?? []; // Avoid undefined index error
$creator = $permissions['allow_create'] ?? 0;
$updater = $permissions['allow_update'] ?? 0;
$destroyer = $permissions['allow_destroy'] ?? 0;
return view('business-industries.index', compact('creator', 'updater', 'destroyer','menuId'));
}
/**
* Show the form for creating a new resource.
*/
public function create()
public function create(Request $request)
{
return view("business-industries.create");
}
/**
* Store a newly created resource in storage.
*/
public function store(Request $request)
{
//
}
/**
* Display the specified resource.
*/
public function show(string $id)
{
//
$menuId = $request->query('menu_id') ?? $request->input('menu_id');
return view("business-industries.create", compact('menuId'));
}
/**
* Show the form for editing the specified resource.
*/
public function edit(string $id)
public function edit(string $id, Request $request)
{
$menuId = $request->query('menu_id') ?? $request->input('menu_id');
$data = BusinessOrIndustry::findOrFail($id);
return view('business-industries.edit', compact('data'));
}
/**
* Update the specified resource in storage.
*/
public function update(Request $request, string $id)
{
//
}
/**
* Remove the specified resource from storage.
*/
public function destroy(string $id)
{
//
return view('business-industries.edit', compact('data', 'menuId'));
}
}

View File

@@ -2,7 +2,54 @@
namespace App\Http\Controllers;
use Illuminate\Support\Facades\Auth;
abstract class Controller
{
//
protected array $permissions = [];
public function __construct()
{
if (!Auth::check()) {
return;
}
$this->setUserPermissions();
}
protected function setUserPermissions()
{
$user = Auth::user();
if (!$user) {
return;
}
$menus = $user->roles()
->with(['menus' => function ($query) {
$query->select('menus.id', 'menus.name')
->withPivot(['allow_show' ,'allow_create', 'allow_update', 'allow_destroy']);
}])
->get()
->pluck('menus')
->flatten()
->unique('id');
// Store permissions in an associative array
foreach ($menus as $menu) {
$this->permissions[$menu->id] = [
'allow_show' => $menu->pivot->allow_show ?? 0,
'allow_create' => $menu->pivot->allow_create ?? 0,
'allow_update' => $menu->pivot->allow_update ?? 0,
'allow_destroy' => $menu->pivot->allow_destroy ?? 0,
];
}
// Share permissions globally in views
view()->share('permissions', $this->permissions);
}
public function getPermissions()
{
return $this->permissions;
}
}

View File

@@ -5,43 +5,33 @@ namespace App\Http\Controllers;
use App\Models\Customer;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\DB;
class CustomersController extends Controller
{
public function index(Request $request)
{
$menuId = $request->query('menu_id');
$user = Auth::user();
$userId = $user->id;
$menuId = $request->query('menu_id') ?? $request->input('menu_id');
$permissions = $this->permissions[$menuId]?? []; // Avoid undefined index error
$creator = $permissions['allow_create'] ?? 0;
$updater = $permissions['allow_update'] ?? 0;
$destroyer = $permissions['allow_destroy'] ?? 0;
// Ambil role_id yang dimiliki user
$roleIds = DB::table('user_role')
->where('user_id', $userId)
->pluck('role_id');
// Ambil data akses berdasarkan role_id dan menu_id
$roleAccess = DB::table('role_menu')
->whereIn('role_id', $roleIds)
->where('menu_id', $menuId)
->first();
// Pastikan roleAccess tidak null sebelum mengakses properti
$creator = $roleAccess->allow_create ?? 0;
$updater = $roleAccess->allow_update ?? 0;
$destroyer = $roleAccess->allow_destroy ?? 0;
return view('customers.index', compact('creator', 'updater', 'destroyer'));
return view('customers.index', compact('creator', 'updater', 'destroyer', 'menuId'));
}
public function create()
public function create(Request $request)
{
return view('customers.create');
$menuId = $request->query('menu_id');
return view('customers.create', compact('menuId'));
}
public function edit(string $id)
public function edit(Request $request, string $id)
{
$data = Customer::findOrFail($id);
return view('customers.edit', compact('data'));
$menuId = $request->query('menu_id');
return view('customers.edit', compact('data', 'menuId'));
}
public function upload(){
return view('customers.upload');
public function upload(Request $request){
$menuId = $request->query('menu_id');
return view('customers.upload', compact('menuId'));
}
}

View File

@@ -4,6 +4,7 @@ namespace App\Http\Controllers\Dashboards;
use App\Http\Controllers\Controller;
use App\Models\ImportDatasource;
use App\Models\Menu;
use Illuminate\Http\Request;
class BigDataController extends Controller
@@ -12,7 +13,8 @@ class BigDataController extends Controller
$latest_import_datasource = ImportDatasource::latest()->first();
$latest_created = $latest_import_datasource ?
$latest_import_datasource->created_at->format("j F Y H:i:s") : null;
return view('dashboards.bigdata', compact('latest_created'));
$menus = Menu::all();
return view('dashboards.bigdata', compact('latest_created', 'menus'));
}
public function pbg()

View File

@@ -0,0 +1,18 @@
<?php
namespace App\Http\Controllers\Dashboards;
use App\Http\Controllers\Controller;
use App\Models\Menu;
use Illuminate\Http\Request;
class PotentialsController extends Controller
{
public function inside_system(){
$menus = Menu::all();
return view('dashboards.potentials.inside_system', compact('menus'));
}
public function outside_system(){
return view('dashboards.potentials.outside_system');
}
}

View File

@@ -15,27 +15,14 @@ class AdvertisementController extends Controller
*/
public function index(Request $request)
{
$menuId = $request->query('menu_id');
$user = Auth::user();
$userId = $user->id;
$menuId = $request->query('menu_id', 0);
$permissions = $this->permissions[$menuId] ?? []; // Avoid undefined index error
// Ambil role_id yang dimiliki user
$roleIds = DB::table('user_role')
->where('user_id', $userId)
->pluck('role_id');
$creator = $permissions['allow_create'] ?? 0;
$updater = $permissions['allow_update'] ?? 0;
$destroyer = $permissions['allow_destroy'] ?? 0;
// Ambil data akses berdasarkan role_id dan menu_id
$roleAccess = DB::table('role_menu')
->whereIn('role_id', $roleIds)
->where('menu_id', $menuId)
->first();
// Pastikan roleAccess tidak null sebelum mengakses properti
$creator = $roleAccess->allow_create ?? 0;
$updater = $roleAccess->allow_update ?? 0;
$destroyer = $roleAccess->allow_destroy ?? 0;
return view('data.advertisements.index', compact('creator', 'updater', 'destroyer'));
return view('data.advertisements.index', compact('creator', 'updater', 'destroyer','menuId'));
}
/**
@@ -50,8 +37,9 @@ class AdvertisementController extends Controller
/**
* Show the form for creating a new resource.
*/
public function create()
public function create(Request $request)
{
$menuId = $request->query('menu_id', 0);
$title = 'Advertisement';
$subtitle = 'Create Data';
@@ -68,14 +56,15 @@ class AdvertisementController extends Controller
// $route = 'advertisements.create';
// info("AdvertisementController@edit diakses dengan ID: $title");
return view('data.advertisements.form', compact('title', 'subtitle', 'fields', 'fieldTypes', 'apiUrl', 'dropdownOptions'));
return view('data.advertisements.form', compact('title', 'subtitle', 'fields', 'fieldTypes', 'apiUrl', 'dropdownOptions','menuId'));
}
/**
* Show the form for editing the specified resource.
*/
public function edit($id)
public function edit(Request $request, $id)
{
$menuId = $request->query('menu_id', 0);
info("AdvertisementController@edit diakses dengan ID: $id");
$title = 'Advertisement';
$subtitle = 'Update Data';
@@ -107,7 +96,7 @@ class AdvertisementController extends Controller
// $route = 'advertisements.update'; // Menggunakan route update untuk form edit
// info("AdvertisementController@edit diakses dengan route: $route");
return view('data.advertisements.form', compact('title', 'subtitle', 'modelInstance', 'fields', 'fieldTypes', 'apiUrl', 'dropdownOptions'));
return view('data.advertisements.form', compact('title', 'subtitle', 'modelInstance', 'fields', 'fieldTypes', 'apiUrl', 'dropdownOptions', 'menuId'));
}
private function getFields()

View File

@@ -0,0 +1,36 @@
<?php
namespace App\Http\Controllers\Data;
use App\Http\Controllers\Controller;
use App\Models\PbgTaskGoogleSheet;
use Illuminate\Http\Request;
class GoogleSheetsController extends Controller
{
/**
* Display a listing of the resource.
*/
public function index(Request $request)
{
$menu_id = $request->query('menu_id');
$user_menu_permission = $this->permissions[$menu_id];
return view('data.google-sheet.index', compact('user_menu_permission'));
}
public function create()
{
return view('data.google-sheet.create');
}
public function show(string $id)
{
$data = PbgTaskGoogleSheet::find($id);
return view('data.google-sheet.show', compact('data'));
}
public function edit(string $id)
{
return view('data.google-sheet.edit');
}
}

View File

@@ -5,8 +5,6 @@ namespace App\Http\Controllers\Data;
use App\Http\Controllers\Controller;
use App\Models\SpatialPlanning;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Auth;
class SpatialPlanningController extends Controller
{
@@ -15,42 +13,31 @@ class SpatialPlanningController extends Controller
*/
public function index(Request $request)
{
$menuId = $request->query('menu_id');
$user = Auth::user();
$userId = $user->id;
$menuId = $request->query('menu_id', 0);
$permissions = $this->permissions[$menuId] ?? []; // Avoid undefined index error
// Ambil role_id yang dimiliki user
$roleIds = DB::table('user_role')
->where('user_id', $userId)
->pluck('role_id');
$creator = $permissions['allow_create'] ?? 0;
$updater = $permissions['allow_update'] ?? 0;
$destroyer = $permissions['allow_destroy'] ?? 0;
// Ambil data akses berdasarkan role_id dan menu_id
$roleAccess = DB::table('role_menu')
->whereIn('role_id', $roleIds)
->where('menu_id', $menuId)
->first();
// Pastikan roleAccess tidak null sebelum mengakses properti
$creator = $roleAccess->allow_create ?? 0;
$updater = $roleAccess->allow_update ?? 0;
$destroyer = $roleAccess->allow_destroy ?? 0;
return view('data.spatialPlannings.index', compact('creator', 'updater', 'destroyer'));
return view('data.spatialPlannings.index', compact('creator', 'updater', 'destroyer','menuId'));
}
/**
* show the form for creating a new resource.
*/
public function bulkCreate()
public function bulkCreate(Request $request)
{
return view('data.spatialPlannings.form-upload');
$menuId = $request->query('menu_id', 0);
return view('data.spatialPlannings.form-upload', compact('menuId'));
}
/**
* Show the form for creating a new resource.
*/
public function create()
public function create(Request $request)
{
$menuId = $request->query('menu_id', 0);
$title = 'Rencana Tata Ruang';
$subtitle = "Create Data";
@@ -61,30 +48,15 @@ class SpatialPlanningController extends Controller
$fieldTypes = $this->getFieldTypes();
$apiUrl = url('/api/spatial-plannings');
return view('data.spatialPlannings.form', compact('title', 'subtitle', 'fields', 'fieldTypes', 'apiUrl', 'dropdownOptions'));
}
/**
* Store a newly created resource in storage.
*/
public function store(Request $request)
{
//
}
/**
* Display the specified resource.
*/
public function show(string $id)
{
//
return view('data.spatialPlannings.form', compact('title', 'subtitle', 'fields', 'fieldTypes', 'apiUrl', 'dropdownOptions','menuId'));
}
/**
* Show the form for editing the specified resource.
*/
public function edit(string $id)
public function edit(Request $request,string $id)
{
$menuId = $request->query('menu_id', 0);
$title = 'Rencana Tata Ruang';
$subtitle = 'Update Data';
@@ -100,23 +72,7 @@ class SpatialPlanningController extends Controller
$fieldTypes = $this->getFieldTypes();
$apiUrl = url('/api/spatial-plannings');
return view('data.spatialPlannings.form', compact('title', 'subtitle', 'modelInstance', 'fields', 'fieldTypes', 'apiUrl', 'dropdownOptions'));
}
/**
* Update the specified resource in storage.
*/
public function update(Request $request, string $id)
{
//
}
/**
* Remove the specified resource from storage.
*/
public function destroy(string $id)
{
//
return view('data.spatialPlannings.form', compact('title', 'subtitle', 'modelInstance', 'fields', 'fieldTypes', 'apiUrl', 'dropdownOptions','menuId'));
}
private function getFields()

View File

@@ -15,41 +15,30 @@ class TourismController extends Controller
*/
public function index(Request $request)
{
$menuId = $request->query('menu_id');
$user = Auth::user();
$userId = $user->id;
$menuId = $request->query('menu_id', 0);
$permissions = $this->permissions[$menuId] ?? []; // Avoid undefined index error
// Ambil role_id yang dimiliki user
$roleIds = DB::table('user_role')
->where('user_id', $userId)
->pluck('role_id');
// Ambil data akses berdasarkan role_id dan menu_id
$roleAccess = DB::table('role_menu')
->whereIn('role_id', $roleIds)
->where('menu_id', $menuId)
->first();
// Pastikan roleAccess tidak null sebelum mengakses properti
$creator = $roleAccess->allow_create ?? 0;
$updater = $roleAccess->allow_update ?? 0;
$destroyer = $roleAccess->allow_destroy ?? 0;
return view('data.tourisms.index', compact('creator', 'updater', 'destroyer'));
$creator = $permissions['allow_create'] ?? 0;
$updater = $permissions['allow_update'] ?? 0;
$destroyer = $permissions['allow_destroy'] ?? 0;
return view('data.tourisms.index', compact('creator', 'updater', 'destroyer', 'menuId'));
}
/**
* show the form for creating a new rsource.
*/
public function bulkCreate()
public function bulkCreate(Request $request)
{
return view('data.tourisms.form-upload');
$menuId = $request->query('menu_id', 0);
return view('data.tourisms.form-upload', compact('menuId'));
}
/**
* Show th form for creating a new resource
*/
public function create()
public function create(Request $request)
{
$menuId = $request->query('menu_id', 0);
$title = 'Pariwisata';
$subtitle = 'Create Data';
@@ -64,14 +53,15 @@ class TourismController extends Controller
$apiUrl = url('/api/tourisms');
return view('data.tourisms.form', compact('title', 'subtitle', 'fields', 'fieldTypes', 'apiUrl', 'dropdownOptions'));
return view('data.tourisms.form', compact('title', 'subtitle', 'fields', 'fieldTypes', 'apiUrl', 'dropdownOptions', 'menuId'));
}
/**
* show the form for editing the specified resource.
*/
public function edit($id)
public function edit(Request $request, $id)
{
$menuId = $request->query('menu_id', 0);
$title = 'Pariwisata';
$subtitle = 'Update Data';
@@ -98,7 +88,7 @@ class TourismController extends Controller
$apiUrl = url('/api/tourisms');
return view('data.tourisms.form', compact('title', 'subtitle', 'modelInstance', 'fields', 'fieldTypes', 'apiUrl', 'dropdownOptions'));
return view('data.tourisms.form', compact('title', 'subtitle', 'modelInstance', 'fields', 'fieldTypes', 'apiUrl', 'dropdownOptions', 'menuId'));
}
private function getFields()

View File

@@ -15,41 +15,30 @@ class UmkmController extends Controller
*/
public function index(Request $request)
{
$menuId = $request->query('menu_id');
$user = Auth::user();
$userId = $user->id;
$menuId = $request->query('menu_id', 0);
$permissions = $this->permissions[$menuId] ?? []; // Avoid undefined index error
// Ambil role_id yang dimiliki user
$roleIds = DB::table('user_role')
->where('user_id', $userId)
->pluck('role_id');
// Ambil data akses berdasarkan role_id dan menu_id
$roleAccess = DB::table('role_menu')
->whereIn('role_id', $roleIds)
->where('menu_id', $menuId)
->first();
// Pastikan roleAccess tidak null sebelum mengakses properti
$creator = $roleAccess->allow_create ?? 0;
$updater = $roleAccess->allow_update ?? 0;
$destroyer = $roleAccess->allow_destroy ?? 0;
return view('data.umkm.index', compact('creator', 'updater', 'destroyer'));
$creator = $permissions['allow_create'] ?? 0;
$updater = $permissions['allow_update'] ?? 0;
$destroyer = $permissions['allow_destroy'] ?? 0;
return view('data.umkm.index', compact('creator', 'updater', 'destroyer', 'menuId'));
}
/**
* Show the form for creating a new resource.
*/
public function bulkCreate()
public function bulkCreate(Request $request)
{
return view('data.umkm.form-upload');
$menuId = $request->query('menu_id', 0);
return view('data.umkm.form-upload', compact('menuId'));
}
/**
* Show the form for creating a new resource.
*/
public function create()
public function create(Request $request)
{
$menuId = $request->query('menu_id', 0);
$title = 'UMKM';
$subtitle = 'Create Data';
@@ -67,14 +56,15 @@ class UmkmController extends Controller
$apiUrl = url('/api/umkm');
return view('data.umkm.form', compact('title', 'subtitle', 'fields', 'fieldTypes', 'apiUrl', 'dropdownOptions'));
return view('data.umkm.form', compact('title', 'subtitle', 'fields', 'fieldTypes', 'apiUrl', 'dropdownOptions','menuId'));
}
/**
* Show the form for editing the specified resource.
*/
public function edit($id)
public function edit(Request $request,$id)
{
$menuId = $request->query('menu_id', 0);
$title = 'UMKM';
$subtitle = 'Update Data';
$modelInstance = Umkm::find($id);
@@ -116,7 +106,7 @@ class UmkmController extends Controller
$apiUrl = url('/api/umkm');
// dd($modelInstance->business_form_id, $dropdownOptions['business_form']);
return view('data.umkm.form', compact('title', 'subtitle', 'modelInstance', 'fields', 'fieldTypes', 'apiUrl', 'dropdownOptions'));
return view('data.umkm.form', compact('title', 'subtitle', 'modelInstance', 'fields', 'fieldTypes', 'apiUrl', 'dropdownOptions','menuId'));
}
private function getFields()

View File

@@ -18,34 +18,21 @@ class DataSettingController extends Controller
*/
public function index(IndexRequest $request)
{
$menuId = $request->query('menu_id');
$user = Auth::user();
$userId = $user->id;
// Ambil role_id yang dimiliki user
$roleIds = DB::table('user_role')
->where('user_id', $userId)
->pluck('role_id');
// Ambil data akses berdasarkan role_id dan menu_id
$roleAccess = DB::table('role_menu')
->whereIn('role_id', $roleIds)
->where('menu_id', $menuId)
->first();
// Pastikan roleAccess tidak null sebelum mengakses properti
$creator = $roleAccess->allow_create ?? 0;
$updater = $roleAccess->allow_update ?? 0;
$destroyer = $roleAccess->allow_destroy ?? 0;
return view("data-settings.index", compact('creator', 'updater', 'destroyer'));
$menuId = $request->query('menu_id') ?? $request->input('menu_id');
$permissions = $this->permissions[$menuId]?? []; // Avoid undefined index error
$creator = $permissions['allow_create'] ?? 0;
$updater = $permissions['allow_update'] ?? 0;
$destroyer = $permissions['allow_destroy'] ?? 0;
return view("data-settings.index", compact('creator', 'updater', 'destroyer','menuId'));
}
/**
* Show the form for creating a new resource.
*/
public function create()
public function create(IndexRequest $request)
{
return view("data-settings.create");
$menuId = $request->query('menu_id') ?? $request->input('menu_id');
return view("data-settings.create", compact('menuId'));
}
/**
@@ -78,14 +65,15 @@ class DataSettingController extends Controller
/**
* Show the form for editing the specified resource.
*/
public function edit(string $id)
public function edit(IndexRequest $request,string $id)
{
try{
$data = DataSetting::findOrFail($id);
$menuId = $request->query('menu_id') ?? $request->input('menu_id');
if(empty($data)){
return redirect()->route('data-settings.index')->with('error', 'Invalid id');
}
return view("data-settings.edit", compact("data"));
return view("data-settings.edit", compact("data", 'menuId'));
}catch(Exception $ex){
return redirect()->route("data-settings.index")->with("error", "Invalid id");
}

View File

@@ -0,0 +1,12 @@
<?php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
class InvitationsController extends Controller
{
public function index(Request $request){
return view('invitations.index');
}
}

View File

@@ -23,32 +23,19 @@ class UsersController extends Controller
return $this->resSuccess($users);
}
public function index(Request $request){
$menuId = $request->query('menu_id');
$user = Auth::user();
$userId = $user->id;
// Ambil role_id yang dimiliki user
$roleIds = DB::table('user_role')
->where('user_id', $userId)
->pluck('role_id');
// Ambil data akses berdasarkan role_id dan menu_id
$roleAccess = DB::table('role_menu')
->whereIn('role_id', $roleIds)
->where('menu_id', $menuId)
->first();
// Pastikan roleAccess tidak null sebelum mengakses properti
$creator = $roleAccess->allow_create ?? 0;
$updater = $roleAccess->allow_update ?? 0;
$destroyer = $roleAccess->allow_destroy ?? 0;
$menuId = $request->query('menu_id') ?? $request->input('menu_id');
$permissions = $this->permissions[$menuId]?? []; // Avoid undefined index error
$creator = $permissions['allow_create'] ?? 0;
$updater = $permissions['allow_update'] ?? 0;
$destroyer = $permissions['allow_destroy'] ?? 0;
$users = User::paginate();
return view('master.users.index', compact('users', 'creator', 'updater', 'destroyer'));
return view('master.users.index', compact('users', 'creator', 'updater', 'destroyer','menuId'));
}
public function create(){
public function create(Request $request){
$menuId = $request->query('menu_id') ?? $request->input('menu_id');
$roles = Role::all();
return view('master.users.create', compact('roles'));
return view('master.users.create', compact('roles', 'menuId'));
}
public function store(UsersRequest $request){
$request->validate([
@@ -86,10 +73,11 @@ class UsersController extends Controller
$user = User::find($id);
return view('master.users.show', compact('user'));
}
public function edit($id){
public function edit(Request $request, $id){
$menuId = $request->query('menu_id') ?? $request->input('menu_id');
$user = User::find($id);
$roles = Role::all();
return view('master.users.edit', compact('user', 'roles'));
return view('master.users.edit', compact('user', 'roles', 'menuId'));
}
public function update(Request $request, $id){
$user = User::find($id);

View File

@@ -6,7 +6,6 @@ use App\Http\Requests\MenuRequest;
use App\Models\Menu;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Auth;
class MenusController extends Controller
{
@@ -15,36 +14,33 @@ class MenusController extends Controller
*/
public function index(Request $request)
{
$menuId = $request->query('menu_id');
$user = Auth::user();
$userId = $user->id;
$menuId = (int) $request->query('menu_id', 0);
$permissions = $this->permissions[$menuId] ?? []; // Avoid undefined index error
// Ambil role_id yang dimiliki user
$roleIds = DB::table('user_role')
->where('user_id', $userId)
->pluck('role_id');
$creator = $permissions['allow_create'] ?? 0;
$updater = $permissions['allow_update'] ?? 0;
$destroyer = $permissions['allow_destroy'] ?? 0;
// Ambil data akses berdasarkan role_id dan menu_id
$roleAccess = DB::table('role_menu')
->whereIn('role_id', $roleIds)
->where('menu_id', $menuId)
->first();
// Pastikan roleAccess tidak null sebelum mengakses properti
$creator = $roleAccess->allow_create ?? 0;
$updater = $roleAccess->allow_update ?? 0;
$destroyer = $roleAccess->allow_destroy ?? 0;
return view('menus.index', compact('creator', 'updater', 'destroyer'));
return view('menus.index', compact('creator', 'updater', 'destroyer', 'menuId'));
}
/**
* Show the form for creating a new resource.
*/
public function create()
public function create(Request $request)
{
$parent_menus = Menu::whereNull('parent_id')->get();
return view("menus.create", compact('parent_menus'));
$menuId = $request->query('menu_id'); // Get menu_id from request
$menu = Menu::with('children')->find($menuId); // Find the menu
// Get IDs of all child menus to exclude
$excludedIds = $menu ? $this->getChildMenuIds($menu) : [$menuId];
// Fetch only menus that have children and are not in the excluded list
$parent_menus = Menu::whereHas('children')
->whereNotIn('id', $excludedIds)
->get();
return view("menus.create", compact('parent_menus', 'menuId'));
}
/**
@@ -77,11 +73,16 @@ class MenusController extends Controller
/**
* Show the form for editing the specified resource.
*/
public function edit(string $id)
public function edit(string $id, Request $request)
{
$menu = Menu::findOrFail($id);
$parent_menus = Menu::whereNull('parent_id')->where('id','!=',$id)->get();
return view("menus.edit", compact('menu','parent_menus'));
$menuId = $request->query('menu_id');
$menu = Menu::with('children')->find($id);
$excludedIds = $menu ? $this->getChildMenuIds($menu) : [$id];
$parent_menus = Menu::whereHas('children')
->whereNotIn('id', $excludedIds)
->get();
return view("menus.edit", compact('menu','parent_menus', 'menuId'));
}
/**
@@ -131,4 +132,15 @@ class MenusController extends Controller
$child->delete();
}
}
private function getChildMenuIds($menu)
{
$ids = [$menu->id]; // Start with current menu ID
foreach ($menu->children as $child) {
$ids = array_merge($ids, $this->getChildMenuIds($child)); // Recursively fetch children
}
return $ids;
}
}

View File

@@ -0,0 +1,64 @@
<?php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
class PaymentRecapsController extends Controller
{
/**
* Display a listing of the resource.
*/
public function index()
{
return view('payment-recaps.index');
}
/**
* Show the form for creating a new resource.
*/
public function create()
{
//
}
/**
* Store a newly created resource in storage.
*/
public function store(Request $request)
{
//
}
/**
* Display the specified resource.
*/
public function show(string $id)
{
//
}
/**
* Show the form for editing the specified resource.
*/
public function edit(string $id)
{
//
}
/**
* Update the specified resource in storage.
*/
public function update(Request $request, string $id)
{
//
}
/**
* Remove the specified resource from storage.
*/
public function destroy(string $id)
{
//
}
}

View File

@@ -0,0 +1,21 @@
<?php
namespace App\Http\Controllers;
use App\Models\PbgTask;
use App\Models\PbgTaskAttachment;
use Illuminate\Http\Request;
class PbgTaskAttachmentsController extends Controller
{
public function show(string $id, Request $request){
try{
$title = $request->get('type') == "berita-acara" ? "Berita Acara" : "Bukti Bayar";
$data = PbgTaskAttachment::findOrFail($id);
$pbg = PbgTask::findOrFail($data->pbg_task_id);
return view('pbg-task-attachment.show', compact('data', 'pbg', 'title'));
}catch(\Exception $e){
return view('pages.404');
}
}
}

View File

@@ -0,0 +1,87 @@
<?php
namespace App\Http\Controllers;
use App\Enums\PbgTaskApplicationTypes;
use App\Enums\PbgTaskStatus;
use App\Http\Resources\TaskAssignmentsResource;
use App\Models\PbgTask;
use App\Models\TaskAssignment;
use Illuminate\Http\Request;
class QuickSearchController extends Controller
{
public function index(){
return view("quick-search.index");
}
public function search_result(Request $request){
$keyword = $request->get("keyword");
return view('quick-search.result', compact('keyword'));
}
public function quick_search_datatable(Request $request)
{
try {
$query = PbgTask::orderBy('id', 'desc');
if ($request->filled('search')) {
$search = $request->get('search');
$query->where(function ($q) use ($search) {
$q->where('name', 'LIKE', "%$search%")
->orWhere('registration_number', 'LIKE', "%$search%")
->orWhere('address', 'LIKE', "%$search%")
->orWhere('document_number', 'LIKE', "%$search%");
});
}
return response()->json($query->paginate());
} catch (\Throwable $e) {
\Log::error("Error fetching datatable data: " . $e->getMessage());
return response()->json([
'message' => 'Terjadi kesalahan saat mengambil data.',
'error' => $e->getMessage(),
], 500);
}
}
public function show($id)
{
try {
$data = PbgTask::with([
'pbg_task_retributions',
'pbg_task_index_integrations',
'pbg_task_retributions.pbg_task_prasarana'
])->findOrFail($id);
$statusOptions = PbgTaskStatus::getStatuses();
$applicationTypes = PbgTaskApplicationTypes::labels();
return view("quick-search.detail", compact("data", 'statusOptions', 'applicationTypes'));
} catch (\Illuminate\Database\Eloquent\ModelNotFoundException $e) {
\Log::warning("PbgTask with ID {$id} not found.");
return redirect()->route('quick-search.index')->with('error', 'Data tidak ditemukan.');
} catch (\Throwable $e) {
\Log::error("Error in QuickSearchController@show: " . $e->getMessage());
return response()->view('pages.404', [], 500); // Optional: create `resources/views/errors/500.blade.php`
}
}
public function task_assignments(Request $request, $uuid){
try{
$query = TaskAssignment::query()
->where('pbg_task_uid', $uuid)
->orderBy('id', 'desc');
if ($request->filled('search')) {
$query->where('name', 'like', "%{$request->get('search')}%")
->orWhere('email', 'like', "%{$request->get('search')}%");
}
return TaskAssignmentsResource::collection($query->paginate(config('app.paginate_per_page', 50)));
}catch(\Exception $exception){
return response()->json(['message' => $exception->getMessage()], 500);
}
}
}

View File

@@ -0,0 +1,14 @@
<?php
namespace App\Http\Controllers\Report;
use App\Http\Controllers\Controller;
use App\Models\Menu;
use Illuminate\Http\Request;
class GrowthReportsController extends Controller
{
public function index(){
return view('report.growth-report.index');
}
}

View File

@@ -15,7 +15,6 @@ class ReportTourismController extends Controller
public function index()
{
$tourismBasedKBLI = TourismBasedKBLI::all();
info($tourismBasedKBLI);
return view('report.tourisms.index', compact('tourismBasedKBLI'));
}
}

View File

@@ -0,0 +1,12 @@
<?php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
class ReportPaymentRecapsController extends Controller
{
public function index(Request $request){
return view('report-payment-recaps.index');
}
}

View File

@@ -0,0 +1,12 @@
<?php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
class ReportPbgPTSPController extends Controller
{
public function index(Request $request){
return view('report-pbg-ptsp.index');
}
}

View File

@@ -2,11 +2,14 @@
namespace App\Http\Controllers\RequestAssignment;
use App\Enums\PbgTaskApplicationTypes;
use App\Enums\PbgTaskFilterData;
use App\Http\Controllers\Controller;
use App\Models\PbgTask;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Auth;
use App\Enums\PbgTaskStatus;
class PbgTaskController extends Controller
{
@@ -15,27 +18,21 @@ class PbgTaskController extends Controller
*/
public function index(Request $request)
{
$menuId = $request->query('menu_id');
$user = Auth::user();
$userId = $user->id;
$menuId = $request->query('menu_id') ?? $request->input('menu_id');
$filter = $request->query('filter');
// Ambil role_id yang dimiliki user
$roleIds = DB::table('user_role')
->where('user_id', $userId)
->pluck('role_id');
// Ambil data akses berdasarkan role_id dan menu_id
$roleAccess = DB::table('role_menu')
->whereIn('role_id', $roleIds)
->where('menu_id', $menuId)
->first();
// Pastikan roleAccess tidak null sebelum mengakses properti
$creator = $roleAccess->allow_create ?? 0;
$updater = $roleAccess->allow_update ?? 0;
$destroyer = $roleAccess->allow_destroy ?? 0;
return view('pbg_task.index', compact('creator', 'updater', 'destroyer'));
$permissions = $this->permissions[$menuId]?? []; // Avoid undefined index error
$creator = $permissions['allow_create'] ?? 0;
$updater = $permissions['allow_update'] ?? 0;
$destroyer = $permissions['allow_destroy'] ?? 0;
return view('pbg_task.index', [
'creator' => $creator,
'updater' => $updater,
'destroyer' => $destroyer,
'filter' => $filter,
'filterOptions' => PbgTaskFilterData::getAllOptions(),
]);
}
/**
@@ -59,8 +56,10 @@ class PbgTaskController extends Controller
*/
public function show(string $id)
{
$data = PbgTask::with(['pbg_task_retributions','pbg_task_index_integrations', 'pbg_task_retributions.pbg_task_prasarana', 'taskAssignments'])->findOrFail($id);
return view("pbg_task.show", compact("data"));
$data = PbgTask::with(['pbg_task_retributions','pbg_task_index_integrations', 'pbg_task_retributions.pbg_task_prasarana'])->findOrFail($id);
$statusOptions = PbgTaskStatus::getStatuses();
$applicationTypes = PbgTaskApplicationTypes::labels();
return view("pbg_task.show", compact("data", 'statusOptions', 'applicationTypes'));
}
/**

View File

@@ -19,35 +19,22 @@ class RolesController extends Controller
*/
public function index(Request $request)
{
$menuId = $request->query('menu_id');
$user = Auth::user();
$userId = $user->id;
$menuId = $request->query('menu_id') ?? $request->input('menu_id');
$permissions = $this->permissions[$menuId]?? []; // Avoid undefined index error
$creator = $permissions['allow_create'] ?? 0;
$updater = $permissions['allow_update'] ?? 0;
$destroyer = $permissions['allow_destroy'] ?? 0;
// Ambil role_id yang dimiliki user
$roleIds = DB::table('user_role')
->where('user_id', $userId)
->pluck('role_id');
// Ambil data akses berdasarkan role_id dan menu_id
$roleAccess = DB::table('role_menu')
->whereIn('role_id', $roleIds)
->where('menu_id', $menuId)
->first();
// Pastikan roleAccess tidak null sebelum mengakses properti
$creator = $roleAccess->allow_create ?? 0;
$updater = $roleAccess->allow_update ?? 0;
$destroyer = $roleAccess->allow_destroy ?? 0;
return view("roles.index", compact('creator', 'updater', 'destroyer'));
return view("roles.index", compact('creator', 'updater', 'destroyer', 'menuId'));
}
/**
* Show the form for creating a new resource.
*/
public function create()
public function create(Request $request)
{
return view("roles.create");
$menuId = $request->query('menu_id');
return view("roles.create", compact('menuId'));
}
/**
@@ -80,10 +67,11 @@ class RolesController extends Controller
/**
* Show the form for editing the specified resource.
*/
public function edit(string $id)
public function edit(string $id, Request $request)
{
$menuId = $request->query('menu_id');
$role = Role::findOrFail($id);
return view("roles.edit", compact('role'));
return view("roles.edit", compact('role', 'menuId'));
}
/**
@@ -121,12 +109,13 @@ class RolesController extends Controller
}
}
public function menu_permission(string $role_id){
public function menu_permission(string $role_id, Request $request){
try{
$menuId = $request->query('menu_id');
$role = Role::findOrFail($role_id);
$menus = Menu::all();
$role_menus = RoleMenu::where('role_id', $role_id)->get() ?? collect();
return view('roles.role_menu', compact('role', 'menus', 'role_menus'));
return view('roles.role_menu', compact('role', 'menus', 'role_menus', 'menuId'));
}catch(\Exception $e){
return redirect()->back()->with("error", $e->getMessage());
}
@@ -134,8 +123,9 @@ class RolesController extends Controller
public function update_menu_permission(Request $request, string $role_id){
try{
$menuId = $request->query('menu_id');
$validateData = $request->validate([
"permissions" => "array",
"permissions" => "nullable|array",
"permissions.*.allow_show" => "nullable|boolean",
"permissions.*.allow_create" => "nullable|boolean",
"permissions.*.allow_update" => "nullable|boolean",
@@ -144,6 +134,13 @@ class RolesController extends Controller
$role = Role::find($role_id);
// Jika `permissions` tidak ada atau kosong, hapus semua permissions terkait
if (!isset($validateData['permissions']) || empty($validateData['permissions'])) {
$role->menus()->detach();
return redirect()->route("roles.index", ['menu_id' => $menuId])
->with('success', 'All menu permissions have been removed.');
}
$permissionsArray = [];
foreach ($validateData['permissions'] as $menu_id => $permission) {
$permissionsArray[$menu_id] = [
@@ -158,7 +155,7 @@ class RolesController extends Controller
// Sync will update existing records and insert new ones
$role->menus()->sync($permissionsArray);
return redirect()->route("role-menu.permission", $role_id)->with('success','Menu Permission updated successfully');
return redirect()->route("roles.index", ['menu_id' => $menuId])->with('success','Menu Permission updated successfully');
}catch(\Exception $e){
Log::error("Error updating role_menu:", ["error" => $e->getMessage()]);
return redirect()->route("role-menu.permission", $role_id)->with("error", $e->getMessage());

View File

@@ -6,6 +6,8 @@ use App\Http\Controllers\Controller;
use App\Services\ServiceSIMBG;
use Illuminate\Http\Request;
use Exception;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\DB;
class SyncronizeController extends Controller
{
protected $service_simbg;

View File

@@ -0,0 +1,28 @@
<?php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
class TpatptsController extends Controller
{
public function index()
{
return view('tpa-tpt.index');
}
public function create()
{
//
}
public function show(string $id)
{
//
}
public function edit(string $id)
{
//
}
}

View File

@@ -2,6 +2,7 @@
namespace App\Http\Resources;
use Carbon\Carbon;
use Illuminate\Http\Request;
use Illuminate\Http\Resources\Json\JsonResource;
@@ -14,13 +15,21 @@ class ImportDatasourceResource extends JsonResource
*/
public function toArray(Request $request): array
{
$startTime = $this->start_time ? Carbon::parse($this->start_time) : null;
$finishTime = $this->finish_time ? Carbon::parse($this->finish_time) : null;
return [
"id"=> $this->id,
"message" => $this->message,
"response_body" => $this->response_body,
"status" => $this->status,
"start_time" => $startTime ? $startTime->toDateTimeString() : null,
"duration" => ($startTime && $finishTime)
? $finishTime->diff($startTime)->format('%H:%I:%S')
: null,
"finish_time" => $finishTime ? $finishTime->toDateTimeString() : null,
"created_at" => $this->created_at->toDateTimeString(),
"updated_at" => $this->updated_at->toDateTimeString(),
"failed_uuid" => $this->failed_uuid
];
}
}

View File

@@ -14,6 +14,16 @@ class MenuResource extends JsonResource
*/
public function toArray(Request $request): array
{
return parent::toArray($request);
// return parent::toArray($request);
return [
'id' => $this->id,
'name' => $this->name,
'icon' => $this->icon,
'url' => $this->url,
'sort_order' => $this->sort_order,
'parent' => $this->parent ? new MenuResource($this->parent) : null,
'created_at' => $this->created_at,
'updated_at' => $this->updated_at
];
}
}

View File

@@ -0,0 +1,19 @@
<?php
namespace App\Http\Resources;
use Illuminate\Http\Request;
use Illuminate\Http\Resources\Json\JsonResource;
class PbgTaskGoogleSheetResource extends JsonResource
{
/**
* Transform the resource into an array.
*
* @return array<string, mixed>
*/
public function toArray(Request $request): array
{
return parent::toArray($request);
}
}

View File

@@ -34,6 +34,14 @@ class RequestAssignmentResouce extends JsonResource
'due_date' => $this->due_date,
'land_certificate_phase' => $this->land_certificate_phase,
'task_created_at' => $this->task_created_at,
'attachment_berita_acara' => $this->attachments
->where('pbg_type', 'berita_acara')
->sortByDesc('created_at')
->first(),
'attachment_bukti_bayar' => $this->attachments
->where('pbg_type', 'bukti_bayar')
->sortByDesc('created_at')
->first(),
];
}
}

View File

@@ -0,0 +1,19 @@
<?php
namespace App\Http\Resources;
use Illuminate\Http\Request;
use Illuminate\Http\Resources\Json\JsonResource;
class TaskAssignmentsResource extends JsonResource
{
/**
* Transform the resource into an array.
*
* @return array<string, mixed>
*/
public function toArray(Request $request): array
{
return parent::toArray($request);
}
}

View File

@@ -0,0 +1,76 @@
<?php
namespace App\Jobs;
use App\Enums\ImportDatasourceStatus;
use App\Models\BigdataResume;
use App\Models\ImportDatasource;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Foundation\Queue\Queueable;
use App\Services\ServiceTabPbgTask;
use App\Services\ServiceGoogleSheet;
use Illuminate\Foundation\Bus\Dispatchable;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Queue\SerializesModels;
class RetrySyncronizeJob implements ShouldQueue
{
use Queueable, Dispatchable, InteractsWithQueue, SerializesModels;
private $import_datasource_id;
public function __construct(int $import_datasource_id)
{
$this->import_datasource_id = $import_datasource_id;
}
/**
* Execute the job.
*/
public function handle(): void
{
try{
$service_tab_pbg_task = app(ServiceTabPbgTask::class);
$service_google_sheet = app(ServiceGoogleSheet::class);
$failed_import = ImportDatasource::find($this->import_datasource_id);
$failed_import->update([
'message' => "Retrying from UUID: ". $failed_import->failed_uuid,
'status' => ImportDatasourceStatus::Processing->value,
'start_time' => now()
]);
$current_failed_uuid = null;
try{
$service_tab_pbg_task->run_service($failed_import->failed_uuid);
}catch(\Exception $e){
$current_failed_uuid = $service_tab_pbg_task->getFailedUUID();
throw $e;
}
$data_setting_result = $service_google_sheet->get_big_resume_data();
BigdataResume::generateResumeData($failed_import->id, "all", $data_setting_result);
BigdataResume::generateResumeData($failed_import->id, now()->year, $data_setting_result);
$failed_import->update([
'status' => ImportDatasourceStatus::Success->value,
'message' => "Retry completed successfully from UUID: ". $failed_import->failed_uuid,
'finish_time' => now(),
'failed_uuid' => null
]);
}catch(\Exception $e){
\Log::error("RetrySyncronizeJob Failed: ". $e->getMessage(), [
'exception' => $e,
]);
if(isset($failed_import)){
$failed_import->update([
'status' => ImportDatasourceStatus::Failed->value,
'message' => "Retry failed from UUID: ". $failed_import->failed_uuid,
'finish_time' => now(),
'failed_uuid' => $current_failed_uuid
]);
}
$this->fail($e);
}
}
}

View File

@@ -0,0 +1,92 @@
<?php
namespace App\Jobs;
use App\Models\BigdataResume;
use App\Models\ImportDatasource;
use App\Services\ServiceGoogleSheet;
use App\Services\ServicePbgTask;
use App\Services\ServiceTabPbgTask;
use App\Services\ServiceTokenSIMBG;
use GuzzleHttp\Client;
use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Foundation\Bus\Dispatchable;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Queue\SerializesModels;
use Illuminate\Support\Facades\Log;
class ScrapingDataJob implements ShouldQueue
{
use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;
/**
* Inject dependencies instead of creating them inside.
*/
public function __construct(
) {
}
/**
* Execute the job.
*/
public function handle()
{
try {
$client = app(Client::class);
$service_pbg_task = app(ServicePbgTask::class);
$service_tab_pbg_task = app(ServiceTabPbgTask::class);
$service_google_sheet = app(ServiceGoogleSheet::class);
$service_token = app(ServiceTokenSIMBG::class);
// Create a record with "processing" status
$import_datasource = ImportDatasource::create([
'message' => 'Initiating scraping...',
'response_body' => null,
'status' => 'processing',
'start_time' => now(),
'failed_uuid' => null
]);
$failed_uuid = null;
// Run the scraping services
$service_google_sheet->run_service();
$service_pbg_task->run_service();
try{
$service_tab_pbg_task->run_service();
}catch(\Exception $e){
$failed_uuid = $service_tab_pbg_task->getFailedUUID();
throw $e;
}
$data_setting_result = $service_google_sheet->get_big_resume_data();
BigdataResume::generateResumeData($import_datasource->id, "all", $data_setting_result);
BigdataResume::generateResumeData($import_datasource->id, now()->year, $data_setting_result);
// Update status to success
$import_datasource->update([
'status' => 'success',
'message' => 'Scraping completed successfully.',
'finish_time' => now()
]);
} catch (\Exception $e) {
Log::error('Scraping failed: ' . $e->getMessage(), ['trace' => $e->getTraceAsString()]);
// Update status to failed
if (isset($import_datasource)) {
$import_datasource->update([
'status' => 'failed',
'response_body' => 'Terjadi kesalahan, Syncronize tidak selesai',
'finish_time' => now(),
'failed_uuid' => $failed_uuid,
]);
}
// Mark the job as failed
$this->fail($e);
}
}
}

View File

@@ -2,8 +2,12 @@
namespace App\Jobs;
use App\Models\ImportDatasource;
use App\Services\GoogleSheetService;
use App\Services\ServiceSIMBG;
use App\Services\ServiceGoogleSheet;
use App\Services\ServicePbgTask;
use App\Services\ServiceTabPbgTask;
use GuzzleHttp\Client;
use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Foundation\Bus\Dispatchable;
@@ -18,11 +22,59 @@ class SyncronizeSIMBG implements ShouldQueue
public function __construct()
{
// Avoid injecting non-serializable dependencies here
}
public function handle(): void
{
$serviceSIMBG = app(ServiceSIMBG::class);
$serviceSIMBG->syncTaskPBG();
$import_datasource = ImportDatasource::where('status', 'processing')->first();
if (!$import_datasource) {
$import_datasource = ImportDatasource::create([
'message' => 'Initiating scraping...',
'response_body' => null,
'status' => 'processing'
]);
}
try {
// Create an instance of GuzzleHttp\Client inside handle()
$client = new Client();
// Create instances of services inside handle()
$service_pbg_task = app(ServicePbgTask::class);
$service_tab_pbg_task = app(ServiceTabPbgTask::class);
// Create a record with "processing" status
// Run the service
$service_google_sheet = new ServiceGoogleSheet();
\Log::info('Starting Google Sheet service');
$service_google_sheet->run_service();
\Log::info('Google Sheet service completed');
\Log::info('Starting PBG Task service');
$service_pbg_task->run_service();
\Log::info('PBG Task service completed');
\Log::info('Starting Tab PBG Task service');
$service_tab_pbg_task->run_service();
\Log::info('Tab PBG Task service completed');
// Update the record status to "success" after completion
$import_datasource->update([
'status' => 'success',
'message' => 'Scraping completed successfully.'
]);
} catch (\Exception $e) {
\Log::error("SyncronizeSIMBG Job Failed: " . $e->getMessage(), [
'exception' => $e,
]);
$import_datasource->update([
'status' => 'failed',
'message' => 'Failed job'
]);
$this->fail($e); // Mark the job as failed
}
}
}

View File

@@ -13,6 +13,9 @@ class ImportDatasource extends Model
'id',
'message',
'response_body',
'status'
'status',
'start_time',
'finish_time',
'failed_uuid'
];
}

View File

@@ -22,4 +22,7 @@ class Menu extends Model
public function children(){
return $this->hasMany(Menu::class,'parent_id');
}
public function parent(){
return $this->belongsTo(Menu::class,'parent_id');
}
}

View File

@@ -46,4 +46,8 @@ class PbgTask extends Model
{
return $this->hasMany(TaskAssignment::class, 'pbg_task_uid', 'uuid');
}
public function attachments(){
return $this->hasMany(PbgTaskAttachment::class, 'pbg_task_id', 'id');
}
}

View File

@@ -0,0 +1,14 @@
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
class PbgTaskAttachment extends Model
{
protected $fillable = ['pbg_task_id', 'file_name', 'file_path', 'pbg_type'];
public function task(){
return $this->belongsTo(PbgTask::class);
}
}

View File

@@ -18,6 +18,13 @@ class RoleMenu extends Model
'allow_destroy',
];
protected $casts = [
'allow_show' => 'boolean',
'allow_create' => 'boolean',
'allow_update' => 'boolean',
'allow_destroy' => 'boolean',
];
public $timestamps = true;
public function role(){

View File

@@ -12,7 +12,7 @@ class TaskAssignment extends Model
protected $fillable = [
'user_id', 'name', 'username', 'email', 'phone_number', 'role',
'role_name', 'is_active', 'file', 'expertise', 'experience',
'is_verif', 'uid', 'status', 'status_name', 'note', 'pbg_task_uid'
'is_verif', 'uid', 'status', 'status_name', 'note', 'pbg_task_uid', 'tas_id'
];
protected $casts = [

View File

@@ -4,6 +4,7 @@ namespace App\Models;
// use Illuminate\Contracts\Auth\MustVerifyEmail;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\SoftDeletes;
use Illuminate\Foundation\Auth\User as Authenticatable;
use Illuminate\Notifications\Notifiable;
use Laravel\Sanctum\HasApiTokens;
@@ -11,7 +12,7 @@ use Laravel\Sanctum\HasApiTokens;
class User extends Authenticatable
{
/** @use HasFactory<\Database\Factories\UserFactory> */
use HasFactory, Notifiable, HasApiTokens;
use HasFactory, Notifiable, HasApiTokens, SoftDeletes;
/**
* The attributes that are mass assignable.
@@ -27,6 +28,8 @@ class User extends Authenticatable
'position'
];
protected $dates = ['deleted_at'];
/**
* The attributes that should be hidden for serialization.
*
@@ -50,7 +53,20 @@ class User extends Authenticatable
];
}
public function delete(){
$this->email = $this->email . '_deleted_'. now()->timestamp;
$this->save();
return parent::delete();
}
public function roles(){
return $this->belongsToMany(Role::class, 'user_role')->withTimestamps();
}
public function menus(){
return Menu::whereHas('roles', function ($query){
$query->whereIn('roles.id', $this->roles->pluck('id'))
->where('role_menu.allow_show', true);
});
}
}

View File

@@ -3,8 +3,13 @@
namespace App\Providers;
use App\Models\Menu;
use App\Services\ServiceGoogleSheet;
use App\Services\ServicePbgTask;
use App\Services\ServiceTabPbgTask;
use App\Services\ServiceTokenSIMBG;
use App\View\Components\Circle;
use Auth;
use GuzzleHttp\Client;
use Illuminate\Support\Facades\Blade;
use Illuminate\Support\Facades\View;
use Illuminate\Support\ServiceProvider;
@@ -19,11 +24,24 @@ class AppServiceProvider extends ServiceProvider
*/
public function register(): void
{
$this->app->singleton(GoogleSheetService::class, function () {
return new GoogleSheetService();
$this->app->bind(Client::class, function () {
return new Client();
});
$this->app->singleton(ServiceSIMBG::class, function ($app) {
return new ServiceSIMBG($app->make(GoogleSheetService::class));
$this->app->bind(ServiceTokenSIMBG::class, function ($app) {
return new ServiceTokenSIMBG();
});
$this->app->bind(ServicePbgTask::class, function ($app) {
return new ServicePbgTask($app->make(Client::class), $app->make(ServiceTokenSIMBG::class));
});
$this->app->bind(ServiceTabPbgTask::class, function ($app) {
return new ServiceTabPbgTask($app->make(Client::class), $app->make(ServiceTokenSIMBG::class));
});
$this->app->bind(ServiceGoogleSheet::class, function ($app) {
return new ServiceGoogleSheet();
});
}
@@ -34,21 +52,24 @@ class AppServiceProvider extends ServiceProvider
{
Blade::component('circle', Circle::class);
View::composer('layouts.partials.sidebar', function ($view){
View::composer('layouts.partials.sidebar', function ($view) {
$user = Auth::user();
if($user){
$menus = Menu::whereHas('roles', function ($query) use ($user){
$query->where('roles.id', $user->roles->pluck('id'));
})
->with(['children' => function ($query) {
$query->whereHas('roles', function ($subQuery) {
$subQuery->where('role_menu.allow_show', 1);
});
}])
->orderBy('sort_order', 'asc')
->get();
}else{
if ($user) {
$menus = Menu::whereHas('roles', function ($query) use ($user) {
$query->whereIn('roles.id', $user->roles->pluck('id'))
->where('role_menu.allow_show', 1);
})
->with(['children' => function ($query) use ($user) {
$query->whereHas('roles', function ($subQuery) use ($user) {
$subQuery->whereIn('roles.id', $user->roles->pluck('id'))
->where('role_menu.allow_show', 1);
});
}])
->whereNull('parent_id') // Ambil hanya menu utama
->orderBy('sort_order', 'asc')
->get();
} else {
$menus = collect();
}

View File

@@ -17,7 +17,7 @@ class RouteServiceProvider extends ServiceProvider
*
* @var string
*/
public const HOME = '/dashboards/bigdata';
public const HOME = '/home';
/**
* Define your route model bindings, pattern filters, and other route configuration.

View File

@@ -27,6 +27,11 @@ class OpenAIService
return "Template prompt tidak ditemukan.";
}
$validationResponse = $this->validatePromptTopic($prompt);
if ($validationResponse !== 'VALID') {
return "Prompt yang Anda masukkan tidak relevan dengan data PUPR/SIMBG/DPUTR atau pekerjaan sejenis.";
}
// Ambil template berdasarkan kategori
$promptTemplate = $jsonData[$mainContent]['prompt'];
@@ -273,4 +278,26 @@ class OpenAIService
// return trim($response['choices'][0]['message']['content'] ?? 'No response');
// }
public function validatePromptTopic($prompt)
{
$messages = [
[
'role' => 'system',
'content' => "You are a classification expert. Determine if the user's request is related to the Indonesian Ministry of Public Works and Public Housing (PUPR), DPUTR, SIMBG, or construction-related tasks managed by these institutions.
Only respond with:
- VALID if it's relevant to those topics
- INVALID if not related at all"
],
['role' => 'user', 'content' => $prompt],
];
$response = $this->client->chat()->create([
'model' => 'gpt-4o-mini',
'messages' => $messages,
]);
return trim($response['choices'][0]['message']['content'] ?? 'INVALID');
}
}

View File

@@ -0,0 +1,321 @@
<?php
namespace App\Services;
use App\Models\DataSetting;
use App\Models\ImportDatasource;
use App\Models\PbgTaskGoogleSheet;
use Carbon\Carbon;
use Exception;
use Google_Client;
use Google_Service_Sheets;
use Log;
class ServiceGoogleSheet
{
protected $client;
protected $service;
protected $spreadsheetID;
protected $service_sheets;
protected $import_datasource;
public function __construct()
{
$this->client = new Google_Client();
$this->client->setApplicationName("Sibedas Google Sheets API");
$this->client->setScopes([Google_Service_Sheets::SPREADSHEETS_READONLY]);
$this->client->setAuthConfig(storage_path("app/teak-banner-450003-s8-ea05661d9db0.json"));
$this->client->setAccessType("offline");
$this->service = new Google_Service_Sheets($this->client);
$this->spreadsheetID = env("SPREAD_SHEET_ID");
$this->service_sheets = new Google_Service_Sheets($this->client);
}
public function run_service(){
try{
$this->sync_big_data();
$this->sync_google_sheet_data();
}catch(Exception $e){
throw $e;
}
}
public function sync_google_sheet_data() {
try {
$sheet_data = $this->get_data_by_sheet(0);
if (empty($sheet_data) || count($sheet_data) < 2) {
Log::warning("sync_google_sheet_data: No valid data found.");
throw new Exception("sync_google_sheet_data: No valid data found.");
}
$cleanValue = function ($value) {
return (isset($value) && trim($value) !== '') ? trim($value) : null;
};
$mapUpsert = [];
foreach(array_slice($sheet_data, 1) as $row){
if(!is_array($row)){
continue;
}
$no_registrasi = $cleanValue($row[2] ?? null);
// Apply the same logic from your SQL UPDATE
if (strpos($no_registrasi, 'PBG-') === 0) {
$format_registrasi = $no_registrasi;
} else {
$format_registrasi = sprintf(
"PBG-%s-%s-%s",
substr($no_registrasi, 0, 6) ?: '',
substr($no_registrasi, 7, 8) ?: '',
substr($no_registrasi, -2) ?: ''
);
}
$mapUpsert[] = [
'jenis_konsultasi' => $cleanValue($row[1] ?? null),
'no_registrasi' => $no_registrasi,
'formatted_registration_number' => $format_registrasi,
'nama_pemilik' => $cleanValue($row[3] ?? null),
'lokasi_bg' => $cleanValue($row[4] ?? null),
'fungsi_bg' => $cleanValue($row[5] ?? null),
'nama_bangunan' => $cleanValue($row[6] ?? null),
'tgl_permohonan' => $this->convertToDate($cleanValue($row[7] ?? null)),
'status_verifikasi' => $cleanValue($row[8] ?? null),
'status_permohonan' => $cleanValue($row[9] ?? null),
'alamat_pemilik' => $cleanValue($row[10] ?? null),
'no_hp' => $cleanValue($row[11] ?? null),
'email' => $cleanValue($row[12] ?? null),
'tanggal_catatan' => $this->convertToDate($cleanValue($row[13] ?? null)),
'catatan_kekurangan_dokumen' => $cleanValue($row[14] ?? null),
'gambar' => $cleanValue($row[15] ?? null),
'krk_kkpr' => $cleanValue($row[16] ?? null),
'no_krk' => $cleanValue($row[17] ?? null),
'lh' => $cleanValue($row[18] ?? null),
'ska' => $cleanValue($row[19] ?? null),
'keterangan' => $cleanValue($row[20] ?? null),
'helpdesk' => $cleanValue($row[21] ?? null),
'pj' => $cleanValue($row[22] ?? null),
'kepemilikan' => $cleanValue($row[24] ?? null),
'potensi_taru' => $cleanValue($row[25] ?? null),
'validasi_dinas' => $cleanValue($row[26] ?? null),
'kategori_retribusi' => $cleanValue($row[27] ?? null),
'no_urut_ba_tpt' => $cleanValue($row[28] ?? null),
'tanggal_ba_tpt' => $this->convertToDate($cleanValue($row[29] ?? null)),
'no_urut_ba_tpa' => $cleanValue($row[30] ?? null),
'tanggal_ba_tpa' => $this->convertToDate($cleanValue($row[31] ?? null)),
'no_urut_skrd' => $cleanValue($row[32] ?? null),
'tanggal_skrd' => $this->convertToDate($cleanValue($row[33] ?? null)),
'ptsp' => $cleanValue($row[34] ?? null),
'selesai_terbit' => $cleanValue($row[35] ?? null),
'tanggal_pembayaran' => $this->convertToDate($cleanValue($row[36] ?? null)),
'format_sts' => $cleanValue($row[37] ?? null),
'tahun_terbit' => (int) $cleanValue($row[38] ?? null),
'tahun_berjalan' => (int) $cleanValue($row[39] ?? null),
'kelurahan' => $cleanValue($row[40] ?? null),
'kecamatan' => $cleanValue($row[41] ?? null),
'lb' => $this->convertToDecimal($cleanValue($row[42] ?? 0)),
'tb' => $this->convertToDecimal($cleanValue($row[43] ?? 0)),
'jlb' => (int) $cleanValue($row[44] ?? null),
'unit' => (int) $cleanValue($row[45] ?? null),
'usulan_retribusi' => (int) $cleanValue($row[46] ?? null),
'nilai_retribusi_keseluruhan_simbg' => $this->convertToDecimal($cleanValue($row[47] ?? 0)),
'nilai_retribusi_keseluruhan_pad' => $this->convertToDecimal($cleanValue($row[48] ?? 0)),
'denda' => $this->convertToDecimal($cleanValue($row[49] ?? 0)),
'latitude' => $cleanValue($row[50] ?? null),
'longitude' => $cleanValue($row[51] ?? null),
'nik_nib' => $cleanValue($row[52] ?? null),
'dok_tanah' => $cleanValue($row[53] ?? null),
'temuan' => $cleanValue($row[54] ?? null),
'updated_at' => now()
];
}
// Count occurrences of each no_registrasi
$registrasiCounts = array_count_values(array_column($mapUpsert, 'no_registrasi'));
// Filter duplicates (those appearing more than once)
$duplicates = array_filter($registrasiCounts, function ($count) {
return $count > 1;
});
if (!empty($duplicates)) {
Log::warning("Duplicate no_registrasi found", ['duplicates' => array_keys($duplicates)]);
}
// Remove duplicates before upsert
$mapUpsert = collect($mapUpsert)->unique('no_registrasi')->values()->all();
$batchSize = 1000;
$chunks = array_chunk($mapUpsert, $batchSize);
foreach ($chunks as $chunk) {
PbgTaskGoogleSheet::upsert($chunk, ['no_registrasi']);
}
Log::info("sync google sheet done");
return true;
} catch (\Exception $e) {
Log::error("sync_google_sheet_data failed", ['error' => $e->getMessage()]);
throw $e;
}
}
public function sync_big_data(){
try {
$sheet_big_data = $this->get_data_by_sheet();
$data_setting_result = []; // Initialize result storage
$found_section = null; // Track which section is found
foreach ($sheet_big_data as $row) {
// Check for section headers
if (in_array("•PROSES PENERBITAN:", $row)) {
$found_section = "MENUNGGU_KLIK_DPMPTSP";
} elseif (in_array("•BERKAS AKTUAL TERVERIFIKASI DINAS TEKNIS 2024:", $row)) {
$found_section = "REALISASI_TERBIT_PBG";
} elseif (in_array("•TERPROSES DI DPUTR: belum selesai rekomtek'", $row)) {
$found_section = "PROSES_DINAS_TEKNIS";
}
// If a section is found and we reach "Grand Total", save the corresponding values
if ($found_section && isset($row[0]) && trim($row[0]) === "Grand Total") {
if ($found_section === "MENUNGGU_KLIK_DPMPTSP") {
$data_setting_result["MENUNGGU_KLIK_DPMPTSP_COUNT"] = $this->convertToInteger($row[2]) ?? null;
$data_setting_result["MENUNGGU_KLIK_DPMPTSP_SUM"] = $this->convertToDecimal($row[3]) ?? null;
} elseif ($found_section === "REALISASI_TERBIT_PBG") {
$data_setting_result["REALISASI_TERBIT_PBG_COUNT"] = $this->convertToInteger($row[2]) ?? null;
$data_setting_result["REALISASI_TERBIT_PBG_SUM"] = $this->convertToDecimal($row[4]) ?? null;
} elseif ($found_section === "PROSES_DINAS_TEKNIS") {
$data_setting_result["PROSES_DINAS_TEKNIS_COUNT"] = $this->convertToInteger($row[2]) ?? null;
$data_setting_result["PROSES_DINAS_TEKNIS_SUM"] = $this->convertToDecimal($row[3]) ?? null;
}
// Reset section tracking after capturing "Grand Total"
$found_section = null;
}
}
foreach ($data_setting_result as $key => $value) {
DataSetting::updateOrInsert(
["key" => $key], // Find by key
["value" => $value] // Update or insert value
);
}
return true;
} catch (\Exception $e) {
// **Log error**
Log::error("Error syncing Google Sheet data", ['error' => $e->getMessage()]);
return false;
}
}
public function get_big_resume_data(){
try {
$sheet_big_data = $this->get_data_by_sheet();
$data_setting_result = []; // Initialize result storage
$found_section = null; // Track which section is found
foreach ($sheet_big_data as $row) {
// Check for section headers
if (in_array("•PROSES PENERBITAN:", $row)) {
$found_section = "MENUNGGU_KLIK_DPMPTSP";
} elseif (in_array("•BERKAS AKTUAL TERVERIFIKASI DINAS TEKNIS 2024:", $row)) {
$found_section = "REALISASI_TERBIT_PBG";
} elseif (in_array("•TERPROSES DI DPUTR: belum selesai rekomtek'", $row)) {
$found_section = "PROSES_DINAS_TEKNIS";
}
// If a section is found and we reach "Grand Total", save the corresponding values
if ($found_section && isset($row[0]) && trim($row[0]) === "Grand Total") {
if ($found_section === "MENUNGGU_KLIK_DPMPTSP") {
$data_setting_result["MENUNGGU_KLIK_DPMPTSP_COUNT"] = $this->convertToInteger($row[2]) ?? null;
$data_setting_result["MENUNGGU_KLIK_DPMPTSP_SUM"] = $this->convertToDecimal($row[3]) ?? null;
} elseif ($found_section === "REALISASI_TERBIT_PBG") {
$data_setting_result["REALISASI_TERBIT_PBG_COUNT"] = $this->convertToInteger($row[2]) ?? null;
$data_setting_result["REALISASI_TERBIT_PBG_SUM"] = $this->convertToDecimal($row[4]) ?? null;
} elseif ($found_section === "PROSES_DINAS_TEKNIS") {
$data_setting_result["PROSES_DINAS_TEKNIS_COUNT"] = $this->convertToInteger($row[2]) ?? null;
$data_setting_result["PROSES_DINAS_TEKNIS_SUM"] = $this->convertToDecimal($row[3]) ?? null;
}
// Reset section tracking after capturing "Grand Total"
$found_section = null;
}
}
return $data_setting_result;
}catch(Exception $exception){
Log::error("Error getting big resume data", ['error' => $exception->getMessage()]);
throw $exception;
}
}
private function get_data_by_sheet($no_sheet = 1){
$spreadsheet = $this->service->spreadsheets->get($this->spreadsheetID);
$sheets = $spreadsheet->getSheets();
$sheetTitle = $sheets[$no_sheet]->getProperties()->getTitle();
$range = "{$sheetTitle}";
$response = $this->service->spreadsheets_values->get($this->spreadsheetID, $range);
$values = $response->getValues();
return!empty($values)? $values : [];
}
private function convertToInteger($value) {
// Check if the value is an empty string, and return null if true
if (trim($value) === "") {
return null;
}
$cleaned = str_replace('.','', $value);
// Otherwise, cast to integer
return (int) $cleaned;
}
private function convertToDecimal(?string $value): ?float
{
if (empty($value)) {
return null; // Return null if the input is empty
}
// Remove all non-numeric characters except comma and dot
$value = preg_replace('/[^0-9,\.]/', '', $value);
// If the number contains both dot (.) and comma (,)
if (strpos($value, '.') !== false && strpos($value, ',') !== false) {
$value = str_replace('.', '', $value); // Remove thousands separator
$value = str_replace(',', '.', $value); // Convert decimal separator to dot
}
// If only a dot is present (assumed as thousands separator)
elseif (strpos($value, '.') !== false) {
$value = str_replace('.', '', $value); // Remove all dots (treat as thousands separators)
}
// If only a comma is present (assumed as decimal separator)
elseif (strpos($value, ',') !== false) {
$value = str_replace(',', '.', $value); // Convert comma to dot (decimal separator)
}
// Ensure the value is numeric before returning
return is_numeric($value) ? (float) number_format((float) $value, 2, '.', '') : null;
}
private function convertToDate($dateString)
{
try {
// Check if the string is empty
if (empty($dateString)) {
return null;
}
// Try to parse the date string
$date = Carbon::parse($dateString);
// Return the Carbon instance
return $date->format('Y-m-d');
} catch (\Exception $e) {
// Return null if an error occurs during parsing
return null;
}
}
}

View File

@@ -0,0 +1,171 @@
<?php
namespace App\Services;
use App\Models\GlobalSetting;
use App\Models\PbgTask;
use Carbon\Carbon;
use GuzzleHttp\Client;
use Exception;
use Illuminate\Support\Facades\Log;
class ServicePbgTask
{
private $client;
private $simbg_host;
private $fetch_per_page;
private $pbg_task_url;
private $service_token;
private $user_token;
private $user_refresh_token;
public function __construct(Client $client, ServiceTokenSIMBG $service_token)
{
$settings = GlobalSetting::whereIn('key', ['SIMBG_HOST', 'FETCH_PER_PAGE'])
->pluck('value', 'key');
$this->simbg_host = trim((string) ($settings['SIMBG_HOST'] ?? ""));
$this->fetch_per_page = trim((string) ($settings['FETCH_PER_PAGE'] ?? "10"));
$this->client = $client;
$this->service_token = $service_token;
$this->pbg_task_url = "{$this->simbg_host}/api/pbg/v1/list/?page=1&size={$this->fetch_per_page}&sort=ASC";
$auth_data = $this->service_token->get_token();
$this->user_token = $auth_data['access'];
$this->user_refresh_token = $auth_data['refresh'];
}
public function run_service()
{
try{
$this->fetch_pbg_task();
}catch(Exception $e){
throw $e;
}
}
private function fetch_pbg_task()
{
try {
$currentPage = 1;
$totalPage = 1;
$options = [
'headers' => [
'Authorization' => "Bearer {$this->user_token}",
'Content-Type' => 'application/json'
]
];
$maxRetries = 3; // Maximum number of retries
$initialDelay = 1; // Initial delay in seconds
$fetchData = function ($url) use (&$options, $maxRetries, $initialDelay) {
$retryCount = 0;
while ($retryCount < $maxRetries) {
try {
return $this->client->get($url, $options);
} catch (\GuzzleHttp\Exception\ClientException $e) {
if ($e->getCode() === 401) {
Log::warning("Unauthorized. Refreshing token...");
// Refresh token
$auth_data = $this->service_token->refresh_token($this->user_refresh_token);
if (!isset($auth_data['access'])) {
Log::error("Token refresh failed.");
throw new Exception("Token refresh failed.");
}
// Update tokens
$this->user_token = $auth_data['access'];
$this->user_refresh_token = $auth_data['refresh'];
// Update headers
$options['headers']['Authorization'] = "Bearer {$this->user_token}";
// Retry request
return $this->client->get($url, $options);
}
throw $e;
} catch (\GuzzleHttp\Exception\ServerException | \GuzzleHttp\Exception\ConnectException $e) {
// Handle 502 or connection issues
if ($e->getCode() === 502) {
Log::warning("502 Bad Gateway - Retrying in {$initialDelay} seconds...");
} else {
Log::error("Network error - Retrying in {$initialDelay} seconds...");
}
$retryCount++;
sleep($initialDelay);
$initialDelay *= 2; // Exponential backoff
}
}
Log::error("Max retries reached. Failing request.");
throw new Exception("Max retries reached. Failing request.");
};
do {
$url = "{$this->simbg_host}/api/pbg/v1/list/?page={$currentPage}&size={$this->fetch_per_page}&sort=ASC";
$fetch_data = $fetchData($url);
if (!$fetch_data) {
Log::error("Failed to fetch data on page {$currentPage} after retries.");
throw new Exception("Failed to fetch data on page {$currentPage} after retries.");
}
$response = json_decode($fetch_data->getBody()->getContents(), true);
if (!isset($response['data'])) {
Log::error("Invalid API response on page {$currentPage}");
throw new Exception("Invalid API response on page {$currentPage}");
}
$data = $response['data'];
$totalPage = isset($response['total_page']) ? (int) $response['total_page'] : 1;
$saved_data = [];
foreach ($data as $item) {
$saved_data[] = [
'uuid' => $item['uid'] ?? null,
'name' => $item['name'] ?? null,
'owner_name' => $item['owner_name'] ?? null,
'application_type' => $item['application_type'] ?? null,
'application_type_name' => $item['application_type_name'] ?? null,
'condition' => $item['condition'] ?? null,
'registration_number' => $item['registration_number'] ?? null,
'document_number' => $item['document_number'] ?? null,
'address' => $item['address'] ?? null,
'status' => $item['status'] ?? null,
'status_name' => $item['status_name'] ?? null,
'slf_status' => $item['slf_status'] ?? null,
'slf_status_name' => $item['slf_status_name'] ?? null,
'function_type' => $item['function_type'] ?? null,
'consultation_type' => $item['consultation_type'] ?? null,
'due_date' => $item['due_date'] ?? null,
'land_certificate_phase' => $item['land_certificate_phase'] ?? null,
'task_created_at' => isset($item['created_at']) ? Carbon::parse($item['created_at'])->format('Y-m-d H:i:s') : null,
'updated_at' => now(),
'created_at' => now(),
];
}
if (!empty($saved_data)) {
PbgTask::upsert($saved_data, ['uuid'], [
'name', 'owner_name', 'application_type', 'application_type_name', 'condition',
'registration_number', 'document_number', 'address', 'status', 'status_name',
'slf_status', 'slf_status_name', 'function_type', 'consultation_type', 'due_date',
'land_certificate_phase', 'task_created_at', 'updated_at'
]);
}
$currentPage++;
} while ($currentPage <= $totalPage);
return true;
} catch (Exception $e) {
Log::error("Error fetching PBG tasks", ['error' => $e->getMessage()]);
throw $e;
}
}
}

View File

@@ -179,60 +179,59 @@ class ServiceSIMBG
}
$mapToUpsert = [];
foreach($sheetData as $data){
$mapToUpsert[] =
[
'no_registrasi' => $data['no__registrasi'] ?? null,
'jenis_konsultasi' => $data['jenis_konsultasi'] ?? null,
'fungsi_bg' => $data['fungsi_bg'] ?? null,
'tgl_permohonan' => $this->convertToDate($data['tgl_permohonan']),
'status_verifikasi' => $data['status_verifikasi'] ?? null,
'status_permohonan' => $this->convertToDate($data['status_permohonan']),
'alamat_pemilik' => $data['alamat_pemilik'] ?? null,
'no_hp' => $data['no__hp'] ?? null,
'email' => $data['e_mail'] ?? null,
'tanggal_catatan' => $this->convertToDate($data['tanggal_catatan']),
'catatan_kekurangan_dokumen' => $data['catatan_kekurangan_dokumen'] ?? null,
'gambar' => $data['gambar'] ?? null,
'krk_kkpr' => $data['krk_kkpr'] ?? null,
'no_krk' => $data['no__krk'] ?? null,
'lh' => $data['lh'] ?? null,
'ska' => $data['ska'] ?? null,
'keterangan' => $data['keterangan'] ?? null,
'helpdesk' => $data['helpdesk'] ?? null,
'pj' => $data['pj'] ?? null,
'kepemilikan' => $data['kepemilikan'] ?? null,
'potensi_taru' => $data['potensi_taru'] ?? null,
'validasi_dinas' => $data['validasi_dinas'] ?? null,
'kategori_retribusi' => $data['kategori_retribusi'] ?? null,
'no_urut_ba_tpt' => $data['no__urut_ba_tpt__2024_0001_'] ?? null,
'tanggal_ba_tpt' => $this->convertToDate($data['tanggal_ba_tpt']),
'no_urut_ba_tpa' => $data['no__urut_ba_tpa'] ?? null,
'tanggal_ba_tpa' => $this->convertToDate($data['tanggal_ba_tpa']),
'no_urut_skrd' => $data['no__urut_skrd__2024_0001_'] ?? null,
'tanggal_skrd' => $this->convertToDate($data['tanggal_skrd']),
'ptsp' => $data['ptsp'] ?? null,
'selesai_terbit' => $data['selesai_terbit'] ?? null,
'tanggal_pembayaran' => $this->convertToDate($data['tanggal_pembayaran__yyyy_mm_dd_']),
'format_sts' => $data['format_sts'] ?? null,
'tahun_terbit' => (int) $data['tahun_terbit'] ?? null,
'tahun_berjalan' => (int) $data['tahun_berjalan'] ?? null,
'kelurahan' => $data['kelurahan'] ?? null,
'kecamatan' => $data['kecamatan'] ?? null,
'lb' => $this->convertToDecimal($data['lb']) ?? null,
'tb' => $this->convertToDecimal($data['tb']) ?? null,
'jlb' => (int) $data['jlb'] ?? null,
'unit' => (int) $data['unit'] ?? null,
'usulan_retribusi' => (int) $data['usulan_retribusi'] ?? null,
'nilai_retribusi_keseluruhan_simbg' => $this->convertToDecimal($data['nilai_retribusi_keseluruhan__simbg_']) ?? null,
'nilai_retribusi_keseluruhan_pad' => $this->convertToDecimal($data['nilai_retribusi_keseluruhan__pad_']) ?? null,
'denda' => $this->convertToDecimal($data['denda']) ?? null,
'latitude' => $data['latitude'] ?? null,
'longitude' => $data['longitude'] ?? null,
'nik_nib' => $data['nik_nib'] ?? null,
'dok_tanah' => $data['dok__tanah'] ?? null,
'temuan' => $data['temuan'] ?? null,
];
foreach ($sheetData as $data) {
$mapToUpsert[] = [
'no_registrasi' => $this->cleanString($data['no__registrasi'] ?? null),
'jenis_konsultasi' => $this->cleanString($data['jenis_konsultasi'] ?? null),
'fungsi_bg' => $this->cleanString($data['fungsi_bg'] ?? null),
'tgl_permohonan' => $this->convertToDate($this->cleanString($data['tgl_permohonan'] ?? null)),
'status_verifikasi' => $this->cleanString($data['status_verifikasi'] ?? null),
'status_permohonan' => $this->convertToDate($this->cleanString($data['status_permohonan'] ?? null)),
'alamat_pemilik' => $this->cleanString($data['alamat_pemilik'] ?? null),
'no_hp' => $this->cleanString($data['no__hp'] ?? null),
'email' => $this->cleanString($data['e_mail'] ?? null),
'tanggal_catatan' => $this->convertToDate($this->cleanString($data['tanggal_catatan'] ?? null)),
'catatan_kekurangan_dokumen' => $this->cleanString($data['catatan_kekurangan_dokumen'] ?? null),
'gambar' => $this->cleanString($data['gambar'] ?? null),
'krk_kkpr' => $this->cleanString($data['krk_kkpr'] ?? null),
'no_krk' => $this->cleanString($data['no__krk'] ?? null),
'lh' => $this->cleanString($data['lh'] ?? null),
'ska' => $this->cleanString($data['ska'] ?? null),
'keterangan' => $this->cleanString($data['keterangan'] ?? null),
'helpdesk' => $this->cleanString($data['helpdesk'] ?? null),
'pj' => $this->cleanString($data['pj'] ?? null),
'kepemilikan' => $this->cleanString($data['kepemilikan'] ?? null),
'potensi_taru' => $this->cleanString($data['potensi_taru'] ?? null),
'validasi_dinas' => $this->cleanString($data['validasi_dinas'] ?? null),
'kategori_retribusi' => $this->cleanString($data['kategori_retribusi'] ?? null),
'no_urut_ba_tpt' => $this->cleanString($data['no__urut_ba_tpt__2024_0001_'] ?? null),
'tanggal_ba_tpt' => $this->convertToDate($this->cleanString($data['tanggal_ba_tpt'] ?? null)),
'no_urut_ba_tpa' => $this->cleanString($data['no__urut_ba_tpa'] ?? null),
'tanggal_ba_tpa' => $this->convertToDate($this->cleanString($data['tanggal_ba_tpa'] ?? null)),
'no_urut_skrd' => $this->cleanString($data['no__urut_skrd__2024_0001_'] ?? null),
'tanggal_skrd' => $this->convertToDate($this->cleanString($data['tanggal_skrd'] ?? null)),
'ptsp' => $this->cleanString($data['ptsp'] ?? null),
'selesai_terbit' => $this->cleanString($data['selesai_terbit'] ?? null),
'tanggal_pembayaran' => $this->convertToDate($this->cleanString($data['tanggal_pembayaran__yyyy_mm_dd_'] ?? null)),
'format_sts' => $this->cleanString($data['format_sts'] ?? null),
'tahun_terbit' => (int) ($data['tahun_terbit'] ?? null),
'tahun_berjalan' => (int) ($data['tahun_berjalan'] ?? null),
'kelurahan' => $this->cleanString($data['kelurahan'] ?? null),
'kecamatan' => $this->cleanString($data['kecamatan'] ?? null),
'lb' => $this->convertToDecimal($data['lb'] ?? null),
'tb' => $this->convertToDecimal($data['tb'] ?? null),
'jlb' => (int) ($data['jlb'] ?? null),
'unit' => (int) ($data['unit'] ?? null),
'usulan_retribusi' => (int) ($data['usulan_retribusi'] ?? null),
'nilai_retribusi_keseluruhan_simbg' => $this->convertToDecimal($data['nilai_retribusi_keseluruhan__simbg_'] ?? null),
'nilai_retribusi_keseluruhan_pad' => $this->convertToDecimal($data['nilai_retribusi_keseluruhan__pad_'] ?? null),
'denda' => $this->convertToDecimal($data['denda'] ?? null),
'latitude' => $this->cleanString($data['latitude'] ?? null),
'longitude' => $this->cleanString($data['longitude'] ?? null),
'nik_nib' => $this->cleanString($data['nik_nib'] ?? null),
'dok_tanah' => $this->cleanString($data['dok__tanah'] ?? null),
'temuan' => $this->cleanString($data['temuan'] ?? null),
];
}
$batchSize = 1000;
@@ -339,20 +338,12 @@ class ServiceSIMBG
$decodedResponse = json_decode($response->getContent(), true);
if (isset($decodedResponse['errors']['code']) && $decodedResponse['errors']['code'] === 'token_not_valid') {
Log::warning("Token is invalid, refreshing token...");
// Regenerate token
$initResToken = $this->getToken();
// Check if new token is valid
if (!empty($initResToken->original['data']['token']['access'])) {
$new_token = $initResToken->original['data']['token']['access'];
// **Fix: Update headers before retrying**
$headers['Authorization'] = "Bearer " . $new_token;
Log::info("Token refreshed successfully, retrying API request...");
continue; // Retry with new token
continue;
} else {
Log::error("Failed to refresh token");
return $this->resError("Failed to refresh token");
@@ -464,29 +455,21 @@ class ServiceSIMBG
'Authorization' => "Bearer " . $token,
];
for ($attempt = 0; $attempt < 2; $attempt++) { // Try twice (original + retry)
for ($attempt = 0; $attempt < 2; $attempt++) {
$res = $this->service_client->get($url, $headers);
// Check if response is JsonResponse and decode it
if ($res instanceof \Illuminate\Http\JsonResponse) {
$decodedResponse = json_decode($res->getContent(), true);
// Handle invalid token case
if (isset($decodedResponse['errors']['code']) && $decodedResponse['errors']['code'] === 'token_not_valid') {
Log::warning("Token is invalid, refreshing token...");
// Regenerate the token
$initResToken = $this->getToken();
// Check if the new token is valid
if (!empty($initResToken->original['data']['token']['access'])) {
$new_token = $initResToken->original['data']['token']['access'];
// **Fix: Update headers with the new token**
$headers['Authorization'] = "Bearer " . $new_token;
Log::info("Token refreshed successfully, retrying API request...");
continue; // Retry the request with the new token
continue;
} else {
Log::error("Failed to refresh token");
return $this->resError("Failed to refresh token");
@@ -494,7 +477,6 @@ class ServiceSIMBG
}
}
// If request succeeds, break out of retry loop
break;
}
@@ -502,7 +484,6 @@ class ServiceSIMBG
$responseData = $res->original ?? [];
$data = $responseData['data']['data'] ?? [];
if (empty($data)) {
Log::error("API response indicates failure", ['url' => $url, 'uuid' => $uuid, 'response' => $responseData]);
return false;
}
@@ -583,7 +564,7 @@ class ServiceSIMBG
foreach ($datas as $data) {
$task_assignments[] = [
'pbg_task_uid' => $uuid, // Assuming this is a foreign key
'pbg_task_uid' => $uuid,
'user_id' => $data['user_id'],
'name' => $data['name'],
'username' => $data['username'],
@@ -592,22 +573,23 @@ class ServiceSIMBG
'role' => $data['role'],
'role_name' => $data['role_name'],
'is_active' => $data['is_active'],
'file' => json_encode($data['file']), // Store as JSON if it's an array
'expertise' => $data['expertise'],
'experience' => $data['experience'],
'file' => !empty($data['file']) ? json_encode($data['file']) : null,
'expertise' => !empty($data['expertise']) ? json_encode($data['expertise']) : null,
'experience' => !empty($data['experience']) ? json_encode($data['experience']) : null,
'is_verif' => $data['is_verif'],
'uid' => $data['uid'], // Unique identifier
'uid' => $data['uid'],
'status' => $data['status'],
'status_name' => $data['status_name'],
'note' => $data['note'],
'ta_id' => $data['id'],
'created_at' => now(),
'updated_at' => now(),
];
}
TaskAssignment::upsert(
$task_assignments, // Data to insert/update
['uid'], // Unique key for conflict resolution
['name', 'username', 'email', 'phone_number', 'role', 'role_name', 'is_active', 'file', 'expertise', 'experience', 'is_verif', 'status', 'status_name', 'note', 'updated_at']
$task_assignments,
['uid'],
['ta_id','name', 'username', 'email', 'phone_number', 'role', 'role_name', 'is_active', 'file', 'expertise', 'experience', 'is_verif', 'status', 'status_name', 'note', 'updated_at']
);
return true;
}catch(Exception $e){
@@ -673,4 +655,9 @@ class ServiceSIMBG
return null;
}
}
private function cleanString($value)
{
return isset($value) ? trim(strip_tags($value)) : null;
}
}

View File

@@ -0,0 +1,426 @@
<?php
namespace App\Services;
use App\Models\GlobalSetting;
use App\Models\PbgTask;
use App\Models\PbgTaskIndexIntegrations;
use App\Models\PbgTaskPrasarana;
use App\Models\PbgTaskRetributions;
use App\Models\TaskAssignment;
use Carbon\Carbon;
use GuzzleHttp\Client;
use Illuminate\Support\Facades\Log;
class ServiceTabPbgTask
{
private $client;
private $simbg_host;
private $fetch_per_page;
private $service_token;
private $user_token;
private $user_refresh_token;
protected $current_uuid = null;
public function __construct(Client $client, ServiceTokenSIMBG $service_token)
{
$settings = GlobalSetting::whereIn('key', ['SIMBG_HOST', 'FETCH_PER_PAGE'])
->pluck('value', 'key');
$this->simbg_host = trim((string) ($settings['SIMBG_HOST'] ?? ""));
$this->fetch_per_page = trim((string) ($settings['FETCH_PER_PAGE'] ?? "10"));
$this->client = $client;
$this->service_token = $service_token;
$auth_data = $this->service_token->get_token();
$this->user_token = $auth_data['access'];
$this->user_refresh_token = $auth_data['refresh'];
}
public function run_service($retry_uuid = null)
{
try {
$pbg_tasks = PbgTask::orderBy('id')->get();
$start = false;
foreach ($pbg_tasks as $pbg_task) {
if($retry_uuid){
if($pbg_task->uuid === $retry_uuid){
$start = true;
}
if(!$start){
continue;
}
}
try{
$this->current_uuid = $pbg_task->uuid;
$this->scraping_task_assignments($pbg_task->uuid);
$this->scraping_task_retributions($pbg_task->uuid);
$this->scraping_task_integrations($pbg_task->uuid);
}catch(\Exception $e){
Log::error("Failed on UUID: {$this->current_uuid}, Error: " . $e->getMessage());
throw $e;
}
}
} catch (\Exception $e) {
Log::error("Failed to syncronize: " . $e->getMessage());
throw $e;
}
}
public function getFailedUUID(){
return $this->current_uuid;
}
private function scraping_task_assignments($uuid)
{
$url = "{$this->simbg_host}/api/pbg/v1/list-tim-penilai/{$uuid}/?page=1&size=10";
$options = [
'headers' => [
'Authorization' => "Bearer {$this->user_token}",
'Content-Type' => 'application/json'
]
];
$maxRetries = 3;
$initialDelay = 1;
$retriedAfter401 = false;
for ($retryCount = 0; $retryCount < $maxRetries; $retryCount++) {
try {
$response = $this->client->get($url, $options);
$responseData = json_decode($response->getBody()->getContents(), true);
if (empty($responseData['data']) || !is_array($responseData['data'])) {
return true;
}
$task_assignments = [];
foreach ($responseData['data'] as $data) {
$task_assignments[] = [
'pbg_task_uid' => $uuid,
'user_id' => $data['user_id'] ?? null,
'name' => $data['name'] ?? null,
'username' => $data['username'] ?? null,
'email' => $data['email'] ?? null,
'phone_number' => $data['phone_number'] ?? null,
'role' => $data['role'] ?? null,
'role_name' => $data['role_name'] ?? null,
'is_active' => $data['is_active'] ?? false,
'file' => !empty($data['file']) ? json_encode($data['file']) : null,
'expertise' => !empty($data['expertise']) ? json_encode($data['expertise']) : null,
'experience' => !empty($data['experience']) ? json_encode($data['experience']) : null,
'is_verif' => $data['is_verif'] ?? false,
'uid' => $data['uid'] ?? null,
'status' => $data['status'] ?? null,
'status_name' => $data['status_name'] ?? null,
'note' => $data['note'] ?? null,
'ta_id' => $data['id'] ?? null,
'created_at' => now(),
'updated_at' => now(),
];
}
if (!empty($task_assignments)) {
TaskAssignment::upsert(
$task_assignments,
['uid'],
['ta_id', 'name', 'username', 'email', 'phone_number', 'role', 'role_name', 'is_active', 'file', 'expertise', 'experience', 'is_verif', 'status', 'status_name', 'note', 'updated_at']
);
}
return $responseData;
} catch (\GuzzleHttp\Exception\ClientException $e) {
if ($e->getCode() === 401 && !$retriedAfter401) {
Log::warning("401 Unauthorized - Refreshing token and retrying...");
try{
$this->refreshToken();
$options['headers']['Authorization'] = "Bearer {$this->user_token}";
$retriedAfter401 = true;
continue;
}catch(\Exception $refreshError){
Log::error("Token refresh and login failed: " . $refreshError->getMessage());
return false;
}
}
throw $e;
} catch (\GuzzleHttp\Exception\ServerException | \GuzzleHttp\Exception\ConnectException $e) {
if ($e->getCode() === 502) {
Log::warning("502 Bad Gateway - Retrying in {$initialDelay} seconds...");
} else {
Log::error("Network error ({$e->getCode()}) - Retrying in {$initialDelay} seconds...");
}
sleep($initialDelay);
$initialDelay *= 2;
} catch (\Exception $e) {
Log::error("Unexpected error: " . $e->getMessage());
throw $e;
}
}
Log::error("Failed to fetch task assignments for UUID {$uuid} after {$maxRetries} retries.");
throw new \Exception("Failed to fetch task assignments for UUID {$uuid} after retries.");
}
private function scraping_task_retributions($uuid)
{
$url = "{$this->simbg_host}/api/pbg/v1/detail/" . $uuid . "/retribution/submit/";
$options = [
'headers' => [
'Authorization' => "Bearer {$this->user_token}",
'Content-Type' => 'application/json'
]
];
$maxRetries = 3;
$initialDelay = 1;
$retriedAfter401 = false;
for ($retryCount = 0; $retryCount < $maxRetries; $retryCount++) {
try {
$response = $this->client->get($url, $options);
$responseData = json_decode($response->getBody()->getContents(), true, 512, JSON_THROW_ON_ERROR);
if (empty($responseData['data']) || !is_array($responseData['data'])) {
return true;
}
$data = $responseData['data'];
$detailCreatedAt = isset($data['created_at'])
? Carbon::parse($data['created_at'])->format('Y-m-d H:i:s')
: null;
$detailUpdatedAt = isset($data['updated_at'])
? Carbon::parse($data['updated_at'])->format('Y-m-d H:i:s')
: null;
$pbg_task_retributions = PbgTaskRetributions::updateOrCreate(
['detail_id' => $data['id']],
[
'detail_uid' => $data['uid'] ?? null,
'detail_created_at' => $detailCreatedAt ?? null,
'detail_updated_at' => $detailUpdatedAt ?? null,
'luas_bangunan' => $data['luas_bangunan'] ?? null,
'indeks_lokalitas' => $data['indeks_lokalitas'] ?? null,
'wilayah_shst' => $data['wilayah_shst'] ?? null,
'kegiatan_id' => $data['kegiatan']['id'] ?? null,
'kegiatan_name' => $data['kegiatan']['name'] ?? null,
'nilai_shst' => $data['nilai_shst'] ?? null,
'indeks_terintegrasi' => $data['indeks_terintegrasi'] ?? null,
'indeks_bg_terbangun' => $data['indeks_bg_terbangun'] ?? null,
'nilai_retribusi_bangunan' => $data['nilai_retribusi_bangunan'] ?? null,
'nilai_prasarana' => $data['nilai_prasarana'] ?? null,
'created_by' => $data['created_by'] ?? null,
'pbg_document' => $data['pbg_document'] ?? null,
'underpayment' => $data['underpayment'] ?? null,
'skrd_amount' => $data['skrd_amount'] ?? null,
'pbg_task_uid' => $uuid,
]
);
$pbg_task_retribution_id = $pbg_task_retributions->id;
$prasaranaData = $data['prasarana'] ?? [];
if (!empty($prasaranaData)) {
$insertData = array_map(fn($item) => [
'pbg_task_uid' => $uuid,
'pbg_task_retribution_id' => $pbg_task_retribution_id,
'prasarana_id' => $item['id'] ?? null,
'prasarana_type' => $item['prasarana_type'] ?? null,
'building_type' => $item['building_type'] ?? null,
'total' => $item['total'] ?? null,
'quantity' => $item['quantity'] ?? null,
'unit' => $item['unit'] ?? null,
'index_prasarana' => $item['index_prasarana'] ?? null,
], $prasaranaData);
PbgTaskPrasarana::upsert($insertData, ['prasarana_id']);
}
return $responseData;
} catch (\GuzzleHttp\Exception\ClientException $e) {
if ($e->getCode() === 401 && !$retriedAfter401) {
Log::warning("401 Unauthorized - Refreshing token and retrying...");
try{
$this->refreshToken();
$options['headers']['Authorization'] = "Bearer {$this->user_token}";
$retriedAfter401 = true;
continue;
}catch(\Exception $refreshError){
Log::error("Token refresh and login failed: " . $refreshError->getMessage());
return false;
}
}
return false;
} catch (\GuzzleHttp\Exception\ServerException | \GuzzleHttp\Exception\ConnectException $e) {
if ($e->getCode() === 502) {
Log::warning("502 Bad Gateway - Retrying in {$initialDelay} seconds...");
} else {
Log::error("Network error ({$e->getCode()}) - Retrying in {$initialDelay} seconds...");
}
sleep($initialDelay);
$initialDelay *= 2;
} catch (\GuzzleHttp\Exception\RequestException $e) {
Log::error("Request error ({$e->getCode()}): " . $e->getMessage());
return false;
} catch (\JsonException $e) {
Log::error("JSON decoding error: " . $e->getMessage());
return false;
} catch (\Throwable $e) {
Log::critical("Unhandled error: " . $e->getMessage(), ['trace' => $e->getTraceAsString()]);
return false;
}
}
Log::error("Failed to fetch task retributions for UUID {$uuid} after retries.");
throw new \Exception("Failed to fetch task retributions for UUID {$uuid} after retries.");
}
private function scraping_task_integrations($uuid){
$url = "{$this->simbg_host}/api/pbg/v1/detail/" . $uuid . "/retribution/indeks-terintegrasi/";
$options = [
'headers' => [
'Authorization' => "Bearer {$this->user_token}",
'Content-Type' => 'application/json'
]
];
$maxRetries = 3;
$initialDelay = 1;
$retriedAfter401 = false;
for ($retryCount = 0; $retryCount < $maxRetries; $retryCount++) {
try {
$response = $this->client->get($url, $options);
$responseData = json_decode($response->getBody()->getContents(), true, 512, JSON_THROW_ON_ERROR);
if (empty($responseData['data']) || !is_array($responseData['data'])) {
return true;
}
$data = $responseData['data'];
$integrations[] = [
'pbg_task_uid' => $uuid,
'indeks_fungsi_bangunan' => $data['indeks_fungsi_bangunan'] ?? null,
'indeks_parameter_kompleksitas' => $data['indeks_parameter_kompleksitas'] ?? null,
'indeks_parameter_permanensi' => $data['indeks_parameter_permanensi'] ?? null,
'indeks_parameter_ketinggian' => $data['indeks_parameter_ketinggian'] ?? null,
'faktor_kepemilikan' => $data['faktor_kepemilikan'] ?? null,
'indeks_terintegrasi' => $data['indeks_terintegrasi'] ?? null,
'total' => $data['total'] ?? null,
];
if (!empty($integrations)) {
PbgTaskIndexIntegrations::upsert($integrations, ['pbg_task_uid'], ['indeks_fungsi_bangunan',
'indeks_parameter_kompleksitas', 'indeks_parameter_permanensi', 'indeks_parameter_ketinggian', 'faktor_kepemilikan', 'indeks_terintegrasi', 'total']);
}
return $responseData;
} catch (\GuzzleHttp\Exception\ClientException $e) {
if ($e->getCode() === 401 && !$retriedAfter401) {
Log::warning("401 Unauthorized - Refreshing token and retrying...");
try{
$this->refreshToken();
$options['headers']['Authorization'] = "Bearer {$this->user_token}";
$retriedAfter401 = true;
continue;
}catch(\Exception $refreshError){
Log::error("Token refresh and login failed: " . $refreshError->getMessage());
return false;
}
}
return false;
} catch (\GuzzleHttp\Exception\ServerException | \GuzzleHttp\Exception\ConnectException $e) {
if ($e->getCode() === 502) {
Log::warning("502 Bad Gateway - Retrying in {$initialDelay} seconds...");
} else {
Log::error("Network error ({$e->getCode()}) - Retrying in {$initialDelay} seconds...");
}
sleep($initialDelay);
$initialDelay *= 2;
} catch (\GuzzleHttp\Exception\RequestException $e) {
Log::error("Request error ({$e->getCode()}): " . $e->getMessage());
return false;
} catch (\JsonException $e) {
Log::error("JSON decoding error: " . $e->getMessage());
return false;
} catch (\Throwable $e) {
Log::critical("Unhandled error: " . $e->getMessage(), ['trace' => $e->getTraceAsString()]);
return false;
}
}
Log::error("Failed to fetch task index integration for UUID {$uuid} after retries.");
throw new \Exception("Failed to fetch task index integration for UUID {$uuid} after retries.");
}
private function refreshToken()
{
$maxRetries = 3; // Maximum retry attempts
$attempt = 0;
while ($attempt < $maxRetries) {
try {
$attempt++;
Log::info("Attempt $attempt: Refreshing token...");
$newAuthToken = $this->service_token->refresh_token($this->user_refresh_token);
if (!isset($newAuthToken['access']) || !isset($newAuthToken['refresh'])) {
throw new \Exception("Invalid refresh token response.");
}
$this->user_token = $newAuthToken['access'];
$this->user_refresh_token = $newAuthToken['refresh'];
Log::info("Token refreshed successfully on attempt $attempt.");
return; // Exit function on success
} catch (\Exception $e) {
Log::error("Token refresh failed on attempt $attempt: " . $e->getMessage());
if ($attempt >= $maxRetries) {
Log::info("Max retries reached. Attempting to log in again...");
break;
}
sleep(30); // Wait for 30 seconds before retrying
}
}
// If refresh fails after retries, attempt re-login
$attempt = 0;
while ($attempt < $maxRetries) {
try {
$attempt++;
Log::info("Attempt $attempt: Re-logging in...");
$loginAgain = $this->service_token->get_token(); // Login again
if (!isset($loginAgain['access']) || !isset($loginAgain['refresh'])) {
throw new \Exception("Invalid login response.");
}
$this->user_token = $loginAgain['access'];
$this->user_refresh_token = $loginAgain['refresh'];
Log::info("Re-login successful on attempt $attempt.");
return; // Exit function on success
} catch (\Exception $e) {
Log::error("Re-login failed on attempt $attempt: " . $e->getMessage());
if ($attempt >= $maxRetries) {
throw new \Exception("Both token refresh and login failed after $maxRetries attempts. " . $e->getMessage());
}
sleep(30); // Wait for 30 seconds before retrying
}
}
}
}

View File

@@ -0,0 +1,79 @@
<?php
namespace App\Services;
use App\Models\GlobalSetting;
use GuzzleHttp\Client;
use GuzzleHttp\Exception\RequestException;
use Illuminate\Support\Facades\Log;
class ServiceTokenSIMBG
{
private $client;
private $login_url;
private $email;
private $password;
private $simbg_host;
private $fetch_per_page;
private $refresh_url;
public function __construct()
{
$settings = GlobalSetting::whereIn('key', [
'SIMBG_EMAIL', 'SIMBG_PASSWORD', 'SIMBG_HOST', 'FETCH_PER_PAGE'
])->pluck('value', 'key');
$this->email = trim((string) ($settings['SIMBG_EMAIL'] ?? ""));
$this->password = trim((string) ($settings['SIMBG_PASSWORD'] ?? ""));
$this->simbg_host = trim((string) ($settings['SIMBG_HOST'] ?? ""));
$this->fetch_per_page = trim((string) ($settings['FETCH_PER_PAGE'] ?? ""));
$this->client = new Client();
$this->login_url = $this->simbg_host . "/api/user/v1/auth/login/";
$this->refresh_url = $this->simbg_host. "/api/user/v1/auth/token/refresh/";
}
public function get_token(){
try {
$response = $this->client->request('POST', $this->login_url, [
'headers' => [
'Content-Type' => 'application/json',
'Accept' => 'application/json',
],
'json' => [
'email' => $this->email,
'password' => $this->password
]
]);
$data = json_decode($response->getBody()->getContents(), true);
return $data['token'];
} catch (RequestException $e) {
Log::error("Failed to get token", [
'error' => $e->getMessage(),
'response' => $e->getResponse() ? $e->getResponse()->getBody()->getContents() : null
]);
return null;
}
}
public function refresh_token(string $refresh_token){
try {
$response = $this->client->request('POST', $this->refresh_url, [
'headers' => [
'Content-Type' => 'application/json',
'Accept' => 'application/json',
],
'json' => [
'refresh' => $refresh_token
]
]);
$data = json_decode($response->getBody()->getContents(), true);
return $data;
} catch (\Throwable $th) {
Log::error("Failed to refresh token", [
'error' => $th->getMessage()
]);
return null;
}
}
}

View File

@@ -13,13 +13,15 @@ class Circle extends Component
public $document_type;
public $document_id;
public $visible_small_circle;
public function __construct($document_id = "",$document_title = "", $document_type = "", $document_color = "#020c5c", $visible_small_circle = true)
public $document_url;
public function __construct($document_id = "",$document_title = "", $document_type = "", $document_color = "#020c5c", $visible_small_circle = true, $document_url = "#")
{
$this->document_title = $document_title;
$this->document_color = $document_color;
$this->document_type = $document_type;
$this->document_id = $document_id;
$this->visible_small_circle = $visible_small_circle;
$this->document_url = $document_url;
}
/**

View File

@@ -10,6 +10,7 @@
"license": "MIT",
"require": {
"php": "^8.2",
"barryvdh/laravel-dompdf": "^3.1",
"google/apiclient": "^2.12",
"guzzlehttp/guzzle": "^7.9",
"laravel/framework": "^11.31",

370
composer.lock generated
View File

@@ -4,8 +4,85 @@
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
"This file is @generated automatically"
],
"content-hash": "41bb51871a746904ab745e4095db8b46",
"content-hash": "e657a4f0a463fa048a0110c08babba93",
"packages": [
{
"name": "barryvdh/laravel-dompdf",
"version": "v3.1.1",
"source": {
"type": "git",
"url": "https://github.com/barryvdh/laravel-dompdf.git",
"reference": "8e71b99fc53bb8eb77f316c3c452dd74ab7cb25d"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/barryvdh/laravel-dompdf/zipball/8e71b99fc53bb8eb77f316c3c452dd74ab7cb25d",
"reference": "8e71b99fc53bb8eb77f316c3c452dd74ab7cb25d",
"shasum": ""
},
"require": {
"dompdf/dompdf": "^3.0",
"illuminate/support": "^9|^10|^11|^12",
"php": "^8.1"
},
"require-dev": {
"larastan/larastan": "^2.7|^3.0",
"orchestra/testbench": "^7|^8|^9|^10",
"phpro/grumphp": "^2.5",
"squizlabs/php_codesniffer": "^3.5"
},
"type": "library",
"extra": {
"laravel": {
"aliases": {
"PDF": "Barryvdh\\DomPDF\\Facade\\Pdf",
"Pdf": "Barryvdh\\DomPDF\\Facade\\Pdf"
},
"providers": [
"Barryvdh\\DomPDF\\ServiceProvider"
]
},
"branch-alias": {
"dev-master": "3.0-dev"
}
},
"autoload": {
"psr-4": {
"Barryvdh\\DomPDF\\": "src"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Barry vd. Heuvel",
"email": "barryvdh@gmail.com"
}
],
"description": "A DOMPDF Wrapper for Laravel",
"keywords": [
"dompdf",
"laravel",
"pdf"
],
"support": {
"issues": "https://github.com/barryvdh/laravel-dompdf/issues",
"source": "https://github.com/barryvdh/laravel-dompdf/tree/v3.1.1"
},
"funding": [
{
"url": "https://fruitcake.nl",
"type": "custom"
},
{
"url": "https://github.com/barryvdh",
"type": "github"
}
],
"time": "2025-02-13T15:07:54+00:00"
},
{
"name": "brick/math",
"version": "0.12.1",
@@ -538,6 +615,161 @@
],
"time": "2024-02-05T11:56:58+00:00"
},
{
"name": "dompdf/dompdf",
"version": "v3.1.0",
"source": {
"type": "git",
"url": "https://github.com/dompdf/dompdf.git",
"reference": "a51bd7a063a65499446919286fb18b518177155a"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/dompdf/dompdf/zipball/a51bd7a063a65499446919286fb18b518177155a",
"reference": "a51bd7a063a65499446919286fb18b518177155a",
"shasum": ""
},
"require": {
"dompdf/php-font-lib": "^1.0.0",
"dompdf/php-svg-lib": "^1.0.0",
"ext-dom": "*",
"ext-mbstring": "*",
"masterminds/html5": "^2.0",
"php": "^7.1 || ^8.0"
},
"require-dev": {
"ext-gd": "*",
"ext-json": "*",
"ext-zip": "*",
"mockery/mockery": "^1.3",
"phpunit/phpunit": "^7.5 || ^8 || ^9 || ^10 || ^11",
"squizlabs/php_codesniffer": "^3.5",
"symfony/process": "^4.4 || ^5.4 || ^6.2 || ^7.0"
},
"suggest": {
"ext-gd": "Needed to process images",
"ext-gmagick": "Improves image processing performance",
"ext-imagick": "Improves image processing performance",
"ext-zlib": "Needed for pdf stream compression"
},
"type": "library",
"autoload": {
"psr-4": {
"Dompdf\\": "src/"
},
"classmap": [
"lib/"
]
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"LGPL-2.1"
],
"authors": [
{
"name": "The Dompdf Community",
"homepage": "https://github.com/dompdf/dompdf/blob/master/AUTHORS.md"
}
],
"description": "DOMPDF is a CSS 2.1 compliant HTML to PDF converter",
"homepage": "https://github.com/dompdf/dompdf",
"support": {
"issues": "https://github.com/dompdf/dompdf/issues",
"source": "https://github.com/dompdf/dompdf/tree/v3.1.0"
},
"time": "2025-01-15T14:09:04+00:00"
},
{
"name": "dompdf/php-font-lib",
"version": "1.0.1",
"source": {
"type": "git",
"url": "https://github.com/dompdf/php-font-lib.git",
"reference": "6137b7d4232b7f16c882c75e4ca3991dbcf6fe2d"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/dompdf/php-font-lib/zipball/6137b7d4232b7f16c882c75e4ca3991dbcf6fe2d",
"reference": "6137b7d4232b7f16c882c75e4ca3991dbcf6fe2d",
"shasum": ""
},
"require": {
"ext-mbstring": "*",
"php": "^7.1 || ^8.0"
},
"require-dev": {
"symfony/phpunit-bridge": "^3 || ^4 || ^5 || ^6"
},
"type": "library",
"autoload": {
"psr-4": {
"FontLib\\": "src/FontLib"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"LGPL-2.1-or-later"
],
"authors": [
{
"name": "The FontLib Community",
"homepage": "https://github.com/dompdf/php-font-lib/blob/master/AUTHORS.md"
}
],
"description": "A library to read, parse, export and make subsets of different types of font files.",
"homepage": "https://github.com/dompdf/php-font-lib",
"support": {
"issues": "https://github.com/dompdf/php-font-lib/issues",
"source": "https://github.com/dompdf/php-font-lib/tree/1.0.1"
},
"time": "2024-12-02T14:37:59+00:00"
},
{
"name": "dompdf/php-svg-lib",
"version": "1.0.0",
"source": {
"type": "git",
"url": "https://github.com/dompdf/php-svg-lib.git",
"reference": "eb045e518185298eb6ff8d80d0d0c6b17aecd9af"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/dompdf/php-svg-lib/zipball/eb045e518185298eb6ff8d80d0d0c6b17aecd9af",
"reference": "eb045e518185298eb6ff8d80d0d0c6b17aecd9af",
"shasum": ""
},
"require": {
"ext-mbstring": "*",
"php": "^7.1 || ^8.0",
"sabberworm/php-css-parser": "^8.4"
},
"require-dev": {
"phpunit/phpunit": "^7.5 || ^8.5 || ^9.5"
},
"type": "library",
"autoload": {
"psr-4": {
"Svg\\": "src/Svg"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"LGPL-3.0-or-later"
],
"authors": [
{
"name": "The SvgLib Community",
"homepage": "https://github.com/dompdf/php-svg-lib/blob/master/AUTHORS.md"
}
],
"description": "A library to read, parse and export to PDF SVG files.",
"homepage": "https://github.com/dompdf/php-svg-lib",
"support": {
"issues": "https://github.com/dompdf/php-svg-lib/issues",
"source": "https://github.com/dompdf/php-svg-lib/tree/1.0.0"
},
"time": "2024-04-29T13:26:35+00:00"
},
{
"name": "dragonmantank/cron-expression",
"version": "v3.4.0",
@@ -2794,6 +3026,73 @@
},
"time": "2022-12-02T22:17:43+00:00"
},
{
"name": "masterminds/html5",
"version": "2.9.0",
"source": {
"type": "git",
"url": "https://github.com/Masterminds/html5-php.git",
"reference": "f5ac2c0b0a2eefca70b2ce32a5809992227e75a6"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/Masterminds/html5-php/zipball/f5ac2c0b0a2eefca70b2ce32a5809992227e75a6",
"reference": "f5ac2c0b0a2eefca70b2ce32a5809992227e75a6",
"shasum": ""
},
"require": {
"ext-dom": "*",
"php": ">=5.3.0"
},
"require-dev": {
"phpunit/phpunit": "^4.8.35 || ^5.7.21 || ^6 || ^7 || ^8 || ^9"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "2.7-dev"
}
},
"autoload": {
"psr-4": {
"Masterminds\\": "src"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Matt Butcher",
"email": "technosophos@gmail.com"
},
{
"name": "Matt Farina",
"email": "matt@mattfarina.com"
},
{
"name": "Asmir Mustafic",
"email": "goetas@gmail.com"
}
],
"description": "An HTML5 parser and serializer.",
"homepage": "http://masterminds.github.io/html5-php",
"keywords": [
"HTML5",
"dom",
"html",
"parser",
"querypath",
"serializer",
"xml"
],
"support": {
"issues": "https://github.com/Masterminds/html5-php/issues",
"source": "https://github.com/Masterminds/html5-php/tree/2.9.0"
},
"time": "2024-03-31T07:05:07+00:00"
},
{
"name": "monolog/monolog",
"version": "3.8.1",
@@ -4695,6 +4994,71 @@
],
"time": "2024-04-27T21:32:50+00:00"
},
{
"name": "sabberworm/php-css-parser",
"version": "v8.7.0",
"source": {
"type": "git",
"url": "https://github.com/MyIntervals/PHP-CSS-Parser.git",
"reference": "f414ff953002a9b18e3a116f5e462c56f21237cf"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/MyIntervals/PHP-CSS-Parser/zipball/f414ff953002a9b18e3a116f5e462c56f21237cf",
"reference": "f414ff953002a9b18e3a116f5e462c56f21237cf",
"shasum": ""
},
"require": {
"ext-iconv": "*",
"php": "^5.6.20 || ^7.0.0 || ~8.0.0 || ~8.1.0 || ~8.2.0 || ~8.3.0 || ~8.4.0"
},
"require-dev": {
"phpunit/phpunit": "5.7.27 || 6.5.14 || 7.5.20 || 8.5.40"
},
"suggest": {
"ext-mbstring": "for parsing UTF-8 CSS"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-main": "9.0.x-dev"
}
},
"autoload": {
"psr-4": {
"Sabberworm\\CSS\\": "src/"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Raphael Schweikert"
},
{
"name": "Oliver Klee",
"email": "github@oliverklee.de"
},
{
"name": "Jake Hotson",
"email": "jake.github@qzdesign.co.uk"
}
],
"description": "Parser for CSS Files written in PHP",
"homepage": "https://www.sabberworm.com/blog/2010/6/10/php-css-parser",
"keywords": [
"css",
"parser",
"stylesheet"
],
"support": {
"issues": "https://github.com/MyIntervals/PHP-CSS-Parser/issues",
"source": "https://github.com/MyIntervals/PHP-CSS-Parser/tree/v8.7.0"
},
"time": "2024-10-27T17:38:32+00:00"
},
{
"name": "symfony/clock",
"version": "v7.2.0",
@@ -9474,12 +9838,12 @@
],
"aliases": [],
"minimum-stability": "stable",
"stability-flags": {},
"stability-flags": [],
"prefer-stable": true,
"prefer-lowest": false,
"platform": {
"php": "^8.2"
},
"platform-dev": {},
"platform-dev": [],
"plugin-api-version": "2.6.0"
}

View File

@@ -79,6 +79,8 @@ return [
'engine' => null,
'options' => extension_loaded('pdo_mysql') ? array_filter([
PDO::MYSQL_ATTR_SSL_CA => env('MYSQL_ATTR_SSL_CA'),
PDO::ATTR_TIMEOUT => 40000,
PDO::MYSQL_ATTR_INIT_COMMAND => "SET SESSION wait_timeout=40000; SET SESSION interactive_timeout=40000;"
]) : [],
],

View File

@@ -108,11 +108,4 @@ return [
'database' => env('DB_CONNECTION', 'sqlite'),
'table' => 'failed_jobs',
],
// set timeout queue
'worker' => [
'timeout' => 300
]
];

View File

@@ -0,0 +1,32 @@
<?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
{
Schema::table('task_assignments', function (Blueprint $table) {
$table->json('expertise')->nullable()->change();
$table->json('experience')->nullable()->change();
$table->bigInteger('ta_id')->nullable()->after('id');
});
}
/**
* Reverse the migrations.
*/
public function down(): void
{
Schema::table('task_assignments', function (Blueprint $table) {
$table->text('expertise')->nullable()->change();
$table->text('experience')->nullable()->change();
$table->dropColumn('ta_id');
});
}
};

View File

@@ -0,0 +1,40 @@
<?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
{
Schema::table('task_assignments', function (Blueprint $table) {
$indexes = DB::select("SHOW INDEXES FROM task_assignments WHERE Key_name = 'task_assignments_email_unique'");
if (!empty($indexes)) {
$table->dropUnique('task_assignments_email_unique');
}
$indexes = DB::select("SHOW INDEXES FROM task_assignments WHERE Key_name = 'task_assignments_username_unique'");
if (!empty($indexes)) {
$table->dropUnique('task_assignments_username_unique');
}
$table->string('email')->nullable()->change();
$table->string('username')->nullable()->change();
});
}
/**
* Reverse the migrations.
*/
public function down(): void
{
Schema::table('task_assignments', function (Blueprint $table) {
//
});
}
};

View File

@@ -0,0 +1,28 @@
<?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
{
Schema::table('users', function (Blueprint $table) {
$table->softDeletes();
});
}
/**
* Reverse the migrations.
*/
public function down(): void
{
Schema::table('users', function (Blueprint $table) {
$table->dropSoftDeletes();
});
}
};

View File

@@ -0,0 +1,29 @@
<?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
{
Schema::table('import_datasources', function (Blueprint $table) {
$table->timestamp('start_time')->nullable();
$table->timestamp('finish_time')->nullable();
});
}
/**
* Reverse the migrations.
*/
public function down(): void
{
Schema::table('import_datasources', function (Blueprint $table) {
$table->dropColumn(['start_time', 'finish_time']);
});
}
};

View File

@@ -0,0 +1,28 @@
<?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
{
Schema::table('import_datasources', function (Blueprint $table) {
$table->string('failed_uuid')->nullable()->after('status');
});
}
/**
* Reverse the migrations.
*/
public function down(): void
{
Schema::table('import_datasources', function (Blueprint $table) {
$table->dropColumn('failed_uuid');
});
}
};

View File

@@ -0,0 +1,32 @@
<?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
{
Schema::dropIfExists('pbg_task_attachments');
Schema::create('pbg_task_attachments', function (Blueprint $table) {
$table->id();
$table->foreignId('pbg_task_id')->constrained('pbg_task')->onDelete('cascade');
$table->string('file_name');
$table->string('file_path');
$table->string('pbg_type');
$table->timestamps();
});
}
/**
* Reverse the migrations.
*/
public function down(): void
{
Schema::dropIfExists('pbg_task_attachments');
}
};

View File

@@ -0,0 +1,26 @@
<?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
{
Schema::table('pbg_task', function(Blueprint $table){
$table->text('address')->nullable()->change();
});
}
/**
* Reverse the migrations.
*/
public function down(): void
{
//
}
};

View File

@@ -15,17 +15,41 @@ class DatabaseSeeder extends Seeder
*/
public function run(): void
{
// User::factory(10)->create();
$users = [
[
'email' => 'user@sibedas.com',
'name' => 'User',
'email_verified_at' => now(),
'password' => Hash::make('password'),
'firstname' => 'user',
'lastname' => 'user',
'position' => 'user',
'remember_token' => Str::random(10),
],
[
'email' => 'superadmin@sibedas.com',
'name' => 'Superadmin',
'email_verified_at' => now(),
'password' => Hash::make('password'),
'firstname' => 'superadmin',
'lastname' => 'superadmin',
'position' => 'superadmin',
'remember_token' => Str::random(10),
],
];
User::factory()->create([
'name' => 'Darkone',
'email' => 'user@demo.com',
'email_verified_at' => now(),
'password' => Hash::make('password'),
'firstname' => 'John',
'lastname' => 'Doe',
'position' => 'crusial',
'remember_token' => Str::random(10),
foreach ($users as $user) {
User::updateOrCreate(
['email' => $user['email']], // Search condition
$user // Update or create with this data
);
}
$this->call([
RoleSeeder::class,
MenuSeeder::class,
UsersRoleMenuSeeder::class,
GlobalSettingSeeder::class,
]);
}
}

View File

@@ -0,0 +1,285 @@
<?php
namespace Database\Seeders;
use Illuminate\Database\Console\Seeds\WithoutModelEvents;
use Illuminate\Database\Seeder;
use App\Models\Menu;
use Illuminate\Support\Arr;
class MenuSeeder extends Seeder
{
/**
* Run the database seeds.
*/
public function run(): void
{
$menus = [
[
"name" => "Neng Bedas",
"url" => "main-chatbot.index",
"icon" => "mingcute:wechat-line",
"parent_id" => null,
"sort_order" => 1,
],
[
"name" => "Dashboard",
"url" => "/dashboard",
"icon" => "mingcute:home-3-line",
"parent_id" => null,
"sort_order" => 2,
"children" => [
[
"name" => "Dashboard Pimpinan",
"url" => "dashboard.home",
"icon" => null,
"sort_order" => 1,
],
[
"name" => "Dashboard PBG",
"url" => "dashboard.pbg",
"icon" => null,
"sort_order" => 2,
],
[
"name" => "Dashboard Potensi",
"url" => '/potentials',
"icon" => null,
"sort_order" => 3,
"children" => [
[
"name" => "Luar Sistem",
"url" => "dashboard.potentials.inside_system",
"icon" => null,
"sort_order" => 1,
],
[
"name" => "Dalam Sistem",
"url" => "dashboard.potentials.outside_system",
"icon" => null,
"sort_order" => 2,
],
]
],
[
"name" => "PETA",
"url" => "dashboard.maps",
"icon" => null,
"sort_order" => 4,
],
],
],
[
"name" => "Master",
"url" => "/master",
"icon" => "mingcute:cylinder-line",
"parent_id" => null,
"sort_order" => 3,
"children" => [
[
"name" => "Users",
"url" => "users.index",
"icon" => null,
"sort_order" => 1,
],
]
],
[
"name" => "Settings",
"url" => "/settings",
"icon" => "mingcute:settings-6-line",
"parent_id" => null,
"sort_order" => 4,
"children" => [
[
"name" => "Syncronize",
"url" => "settings.syncronize",
"icon" => null,
"sort_order" => 1,
],
[
"name" => "Menu",
"url" => "menus.index",
"icon" => null,
"sort_order" => 2,
],
[
"name" => "Role",
"url" => "roles.index",
"icon" => null,
"sort_order" => 3,
],
]
],
[
"name" => "Data Settings",
"url" => "/data-settings",
"icon" => "mingcute:settings-1-line",
"parent_id" => null,
"sort_order" => 5,
"children" => [
[
"name" => "Setting Dashboard",
"url" => "data-settings.index",
"icon" => null,
"sort_order" => 1,
],
]
],
[
"name" => "Data",
"url" => "/data",
"icon" => "mingcute:task-line",
"parent_id" => null,
"sort_order" => 6,
"children" => [
[
"name" => "PBG",
"url" => "pbg-task.index",
"icon" => null,
"sort_order" => 1,
],
[
"name" => "Reklame",
"url" => "web-advertisements.index",
"icon" => null,
"sort_order" => 2,
],
[
"name" => "Usaha atau Industri",
"url" => "business-industries.index",
"icon" => null,
"sort_order" => 3,
],
[
"name" => "UMKM",
"url" => "web-umkm.index",
"icon" => null,
"sort_order" => 4,
],
[
"name" => "Pariwisata",
"url" => "web-tourisms.index",
"icon" => null,
"sort_order" => 5,
],
[
"name" => "Tata Ruang",
"url" => "web-spatial-plannings.index",
"icon" => null,
"sort_order" => 6,
],
[
"name" => "PDAM",
"url" => "customers",
"icon" => null,
"sort_order" => 7,
],
[
"name" => "Google Sheets",
"url" => "google-sheets",
"icon" => null,
"sort_order" => 8,
],
[
"name" => "TPA TPT",
"url" => "tpa-tpt.index",
"icon" => null,
"sort_order" => 9,
],
]
],
[
"name" => "Laporan",
"url" => "/laporan",
"icon" => "mingcute:report-line",
"parent_id" => null,
"sort_order" => 7,
"children" => [
[
"name" => "Lap Pariwisata",
"url" => "tourisms-report.index",
"icon" => null,
"sort_order" => 1,
],
[
"name" => "Lap Pimpinan",
"url" => "bigdata-resumes",
"icon" => null,
"sort_order" => 2,
],
[
"name" => "Lap Pertumbuhan",
"url" => "growths",
"icon" => null,
"sort_order" => 3,
],
[
"name" => "Rekap Pembayaran",
"url" => "payment-recaps",
"icon" => null,
"sort_order" => 4,
],
[
"name" => "Lap Rekap Data Pembayaran",
"url" => "report-payment-recaps",
"icon" => null,
"sort_order" => 5,
],
[
"name" => "Lap PBG (PTSP)",
"url" => "report-pbg-ptsp",
"icon" => null,
"sort_order" => 6,
],
]
],
[
"name" => "Approval",
"url" => "/approval",
"icon" => "mingcute:user-follow-2-line",
"parent_id" => null,
"sort_order" => 8,
"children" => [
[
"name" => "Approval Pejabat",
"url" => "approval-list",
"icon" => null,
"sort_order" => 1,
],
]
],
[
"name" => "Tools",
"url" => "/tools",
"icon" => "mingcute:tool-line",
"parent_id" => null,
"sort_order" => 9,
"children" => [
[
"name" => "Undangan",
"url" => "invitations",
"icon" => null,
"sort_order" => 1,
],
]
],
];
foreach ($menus as $menuData) {
$this->createOrUpdateMenu($menuData);
}
}
private function createOrUpdateMenu($menuData, $parentId = null){
$menuData['parent_id'] = $parentId;
$menu = Menu::updateOrCreate(['name' => $menuData['name']], Arr::except($menuData, ['children']));
if(!empty($menuData['children'])){
foreach($menuData['children'] as $child){
$this->createOrUpdateMenu($child, $menu->id);
}
}
}
}

View File

@@ -0,0 +1,33 @@
<?php
namespace Database\Seeders;
use App\Models\Role;
use Illuminate\Database\Console\Seeds\WithoutModelEvents;
use Illuminate\Database\Seeder;
class RoleSeeder extends Seeder
{
/**
* Run the database seeds.
*/
public function run(): void
{
$roles = [
[
"name" => "superadmin",
"description" => "show all menus for super admins",
],
[
"name" => "operator",
"description" => "show only necessary menus for operators",
],
[
"name" => "user",
"description" => "show only necessary menus for users",
]
];
Role::upsert($roles, ['name']);
}
}

View File

@@ -13,301 +13,64 @@ class UsersRoleMenuSeeder extends Seeder
/**
* Run the database seeds.
*/
public function run(): void
public function run(): void
{
$roles = [
[
"name" => "superadmin",
"description" => "show all menus for super admins",
// Fetch roles in a single query
$roles = Role::whereIn('name', ['superadmin', 'user', 'operator'])->get()->keyBy('name');
// Fetch all menus in a single query and index by name
$menus = Menu::whereIn('name', [
'Dashboard', 'Master', 'Settings', 'Data Settings', 'Data', 'Laporan', 'Neng Bedas',
'Approval', 'Tools', 'Dashboard Pimpinan', 'Dashboard PBG', 'Users', 'Syncronize',
'Menu', 'Role', 'Setting Dashboard', 'PBG', 'Reklame', 'Usaha atau Industri', 'Pariwisata',
'Lap Pariwisata', 'UMKM', 'Dashboard Potensi', 'Tata Ruang', 'PDAM', 'PETA',
'Lap Pimpinan', 'Dalam Sistem', 'Luar Sistem', 'Google Sheets', 'TPA TPT',
'Approval Pejabat', 'Undangan', 'Rekap Pembayaran', 'Lap Rekap Data Pembayaran', 'Lap PBG (PTSP)', 'Lap Pertumbuhan'
])->get()->keyBy('name');
// Define access levels for each role
$permissions = [
'superadmin' => [
'Dashboard', 'Master', 'Settings', 'Data Settings', 'Data', 'Laporan', 'Neng Bedas',
'Approval', 'Tools', 'Dashboard Pimpinan', 'Dashboard PBG', 'Users', 'Syncronize',
'Menu', 'Role', 'Setting Dashboard', 'PBG', 'Reklame', 'Usaha atau Industri', 'Pariwisata',
'Lap Pariwisata', 'UMKM', 'Dashboard Potensi', 'Tata Ruang', 'PDAM', 'Dalam Sistem',
'Luar Sistem', 'Lap Pimpinan', 'Google Sheets', 'TPA TPT', 'Approval Pejabat',
'Undangan', 'Rekap Pembayaran', 'Lap Rekap Data Pembayaran', 'Lap PBG (PTSP)', 'Lap Pertumbuhan'
],
[
"name" => "admin",
"description" => "show only necessary menus for admins",
],
[
"name" => "operator",
"description" => "show only necessary menus for operators",
]
'user' => ['Dashboard', 'Data', 'Laporan', 'Neng Bedas',
'Approval', 'Tools', 'Dashboard Pimpinan', 'Dashboard PBG', 'Users', 'Syncronize',
'Menu', 'Role', 'Setting Dashboard', 'PBG', 'Reklame', 'Usaha atau Industri', 'Pariwisata',
'Lap Pariwisata', 'UMKM', 'Dashboard Potensi', 'Tata Ruang', 'PDAM', 'Dalam Sistem',
'Luar Sistem', 'Lap Pimpinan', 'Google Sheets', 'TPA TPT', 'Approval Pejabat',
'Undangan', 'Rekap Pembayaran', 'Lap Rekap Data Pembayaran', 'Lap PBG (PTSP)'],
'operator' => ['Dashboard', 'Data', 'Laporan']
];
Role::upsert($roles, ['name']);
// Define permission levels
$superadminPermissions = ["allow_show" => true, "allow_create" => true, "allow_update" => true, "allow_destroy" => true];
$userPermissions = ["allow_show" => true, "allow_create" => false, "allow_update" => false, "allow_destroy" => false];
$operatorPermissions = ["allow_show" => true, "allow_create" => false, "allow_update" => false, "allow_destroy" => false];
$parent_menus = [
[
"name" => "Dashboard",
"url" => "/dashboard",
"icon" => "mingcute:home-3-line",
"parent_id" => null,
"sort_order" => 1,
],
[
"name" => "Master",
"url" => "/master",
"icon" => "mingcute:cylinder-line",
"parent_id" => null,
"sort_order" => 2,
],
[
"name" => "Settings",
"url" => "/settings",
"icon" => "mingcute:settings-6-line",
"parent_id" => null,
"sort_order" => 3,
],
[
"name" => "Data Settings",
"url" => "/data-settings",
"icon" => "mingcute:settings-1-line",
"parent_id" => null,
"sort_order" => 4,
],
[
"name" => "Data",
"url" => "/data",
"icon" => "mingcute:task-line",
"parent_id" => null,
"sort_order" => 5,
],
[
"name" => "Laporan",
"url" => "/laporan",
"icon" => "mingcute:report-line",
"parent_id" => null,
"sort_order" => 6,
],
[
"name" => "Neng Bedas",
"url" => "/chat",
"icon" => "mingcute:wechat-line",
"parent_id" => null,
"sort_order" => 7,
]
];
foreach ($parent_menus as $parent_menu) {
Menu::firstOrCreate(['name' => $parent_menu['name']], $parent_menu);
// Assign menus to roles
foreach ($permissions as $roleName => $menuNames) {
$role = $roles[$roleName] ?? null;
if ($role) {
$role->menus()->sync(
collect($menuNames)->mapWithKeys(fn($menuName) => [
$menus[$menuName]->id => ($roleName === 'superadmin' ? $superadminPermissions :
($roleName === 'operator' ? $operatorPermissions : $userPermissions))
])->toArray()
);
}
}
// Attach Menus to Roles
$superadmin = Role::where('name', 'superadmin')->first();
$admin = Role::where('name', 'admin')->first();
$operator = Role::where('name', 'operator')->first();
$dashboard = Menu::where('name', 'Dashboard')->first();
$master = Menu::where('name', 'Master')->first();
$settings = Menu::where('name', 'Settings')->first();
$dataSettings = Menu::where('name', 'Data Settings')->first();
$data = Menu::where('name', 'Data')->first();
$laporan = Menu::where('name', 'Laporan')->first();
$chat_bedas = Menu::where('name', 'Neng Bedas')->first();
// create children menu
$children_menus = [
[
"name" => "Dashboard Pimpinan",
"url" => "dashboard.home",
"icon" => null,
"parent_id" => $dashboard->id,
"sort_order" => 1,
],
[
"name" => "Dashboard PBG",
"url" => "dashboard.pbg",
"icon" => null,
"parent_id" => $dashboard->id,
"sort_order" => 2,
],
[
"name" => "Dashboard Potensi",
"url" => "dashboard.lack_of_potential",
"icon" => null,
"parent_id" => $dashboard->id,
"sort_order" => 3,
],
[
"name" => "PETA",
"url" => "dashboard.maps",
"icon" => null,
"parent_id" => $dashboard->id,
"sort_order" => 4,
],
[
"name" => "Users",
"url" => "users.index",
"icon" => null,
"parent_id" => $master->id,
"sort_order" => 1,
],
[
"name" => "Syncronize",
"url" => "settings.syncronize",
"icon" => null,
"parent_id" => $settings->id,
"sort_order" => 1,
],
[
"name" => "Menu",
"url" => "menus.index",
"icon" => null,
"parent_id" => $settings->id,
"sort_order" => 2,
],
[
"name" => "Role",
"url" => "roles.index",
"icon" => null,
"parent_id" => $settings->id,
"sort_order" => 3,
],
[
"name" => "Setting Dashboard",
"url" => "data-settings.index",
"icon" => null,
"parent_id" => $dataSettings->id,
"sort_order" => 1,
],
[
"name" => "PBG",
"url" => "pbg-task.index",
"icon" => null,
"parent_id" => $data->id,
"sort_order" => 1,
],
[
"name" => "Reklame",
"url" => "web.advertisements.index",
"icon" => null,
"parent_id" => $data->id,
"sort_order" => 2,
],
[
"name" => "Usaha atau Industri",
"url" => "business-industries.index",
"icon" => null,
"parent_id" => $data->id,
"sort_order" => 3,
],
[
"name" => "UMKM",
"url" => "web-umkm.index",
"icon" => null,
"parent_id" => $data->id,
"sort_order" => 4,
],
[
"name" => "Pariwisata",
"url" => "web-tourisms.index",
"icon" => null,
"parent_id" => $data->id,
"sort_order" => 5,
],
[
"name" => "Tata Ruang",
"url" => "web-spatial-plannings.index",
"icon" => null,
"parent_id" => $data->id,
"sort_order" => 6,
],
[
"name" => "PDAM",
"url" => "customers",
"icon" => null,
"parent_id" => $data->id,
"sort_order" => 7,
],
[
"name" => "Lap Pariwisata",
"url" => "tourisms-report.index",
"icon" => null,
"parent_id" => $laporan->id,
"sort_order" => 1,
],
[
"name" => "Lap Pimpinan",
"url" => "bigdata-resumes",
"icon" => null,
"parent_id" => $laporan->id,
"sort_order" => 2,
],
[
"name" => "Chat",
"url" => "main-chatbot.index",
"icon" => null,
"parent_id" => $chat_bedas->id,
"sort_order" => 1,
],
];
foreach ($children_menus as $child_menu) {
Menu::firstOrCreate(['name' => $child_menu['name']], $child_menu);
}
$dashboard_pimpinan = Menu::where('name', 'Dashboard Pimpinan')->first();
$dashboard_pbg = Menu::where('name', 'Dashboard PBG')->first();
$users = Menu::where('name', 'Users')->first();
$syncronize = Menu::where('name', 'Syncronize')->first();
$setting_menu = Menu::where('name', 'Menu')->first();
$setting_role = Menu::where('name', 'Role')->first();
$setting_dashboard = Menu::where('name', 'Setting Dashboard')->first();
$setting_pbg = Menu::where('name', 'PBG')->first();
$reklame = Menu::where('name', 'Reklame')->first();
$businessIndustries = Menu::where('name', 'Usaha atau Industri')->first();
$pariwisata = Menu::where('name', 'Pariwisata')->first();
$laporan_pariwisata = Menu::where('name', 'Lap Pariwisata')->first();
$umkm = Menu::where('name', 'UMKM')->first();
$lack_of_potentials = Menu::where('name', 'Dashboard Potensi')->first();
$spatial_plannings = Menu::where('name', 'Tata Ruang')->first();
$pdam = Menu::where('name', 'PDAM')->first();
$peta = Menu::where('name', 'PETA')->first();
$bigdata_resume = Menu::where('name', 'Lap Pimpinan')->first();
$chatbot = Menu::where('name', 'Chat')->first();
// Superadmin gets all menus
$superadmin->menus()->sync([
// parent
$dashboard->id => ["allow_show" => true, "allow_create" => false, "allow_update" => false, "allow_destroy" => false],
$master->id => ["allow_show" => true, "allow_create" => false, "allow_update" => false, "allow_destroy" => false],
$settings->id => ["allow_show" => true, "allow_create" => false, "allow_update" => false, "allow_destroy" => false],
$dataSettings->id => ["allow_show" => true, "allow_create" => false, "allow_update" => false, "allow_destroy" => false],
$data->id => ["allow_show" => true, "allow_create" => false, "allow_update" => false, "allow_destroy" => false],
$laporan->id => ["allow_show" => true, "allow_create" => false, "allow_update" => false, "allow_destroy" => false],
$chat_bedas->id => ["allow_show" => true, "allow_create" => false, "allow_update" => false, "allow_destroy" => false],
// children
$dashboard_pimpinan->id => ["allow_show" => true, "allow_create" => true, "allow_update" => true, "allow_destroy" => true],
$dashboard_pbg->id => ["allow_show" => true, "allow_create" => true, "allow_update" => true, "allow_destroy" => true],
$users->id => ["allow_show" => true, "allow_create" => true, "allow_update" => true, "allow_destroy" => true],
$syncronize->id => ["allow_show" => true, "allow_create" => true, "allow_update" => true, "allow_destroy" => true],
$setting_menu->id => ["allow_show" => true, "allow_create" => true, "allow_update" => true, "allow_destroy" => true],
$setting_role->id => ["allow_show" => true, "allow_create" => true, "allow_update" => true, "allow_destroy" => true],
$setting_dashboard->id => ["allow_show" => true, "allow_create" => true, "allow_update" => true, "allow_destroy" => true],
$setting_pbg->id => ["allow_show" => true, "allow_create" => true, "allow_update" => true, "allow_destroy" => true],
$reklame->id => ["allow_show" => true, "allow_create" => true, "allow_update" => true, "allow_destroy" => true],
$businessIndustries->id => ["allow_show" => true, "allow_create" => true, "allow_update" => true, "allow_destroy" => true],
$pariwisata->id => ["allow_show" => true, "allow_create" => true, "allow_update" => true, "allow_destroy" => true],
$laporan_pariwisata->id => ["allow_show" => true, "allow_create" => true, "allow_update" => true, "allow_destroy" => true],
$umkm->id => ["allow_show" => true, "allow_create" => true, "allow_update" => true, "allow_destroy" => true],
$lack_of_potentials->id => ["allow_show" => true, "allow_create" => true, "allow_update" => true, "allow_destroy" => true],
$spatial_plannings->id => ["allow_show" => true, "allow_create" => true, "allow_update" => true, "allow_destroy" => true],
$pdam->id => ["allow_show" => true, "allow_create" => true, "allow_update" => true, "allow_destroy" => true],
$peta->id => ["allow_show" => true, "allow_create" => true, "allow_update" => true, "allow_destroy" => true],
$bigdata_resume->id => ["allow_show" => true, "allow_create" => true, "allow_update" => true, "allow_destroy" => true],
$chatbot->id => ["allow_show" => true, "allow_create" => true, "allow_update" => true, "allow_destroy" => true],
]);
// Admin gets limited menus
$admin->menus()->sync([
$dashboard->id => ["allow_show" => true, "allow_create" => true, "allow_update" => true, "allow_destroy" => true],
$master->id => ["allow_show" => true, "allow_create" => true, "allow_update" => true, "allow_destroy" => true],
$settings->id => ["allow_show" => true, "allow_create" => true, "allow_update" => true, "allow_destroy" => true],
]);
// Operator gets only basic menus with full permissions
$operator->menus()->sync([
$dashboard->id => ["allow_show" => true, "allow_create" => true, "allow_update" => true, "allow_destroy" => true],
$data->id => ["allow_show" => true, "allow_create" => true, "allow_update" => true, "allow_destroy" => true],
]);
// Attach User to role super admin
User::findOrFail(1)->roles()->sync([$superadmin->id]);
$accountSuperadmin = User::where('email', 'superadmin@sibedas.com')->first();
$accountUser = User::where('email', 'user@sibedas.com')->first();
$accountDefault = User::where('email','user@demo.com')->first();
$accountSuperadmin->roles()->sync([$roles['superadmin']->id]);
$accountUser->roles()->sync([$roles['user']->id]);
$accountDefault->roles()->sync([$roles['user']->id]);
}
}

View File

@@ -19,16 +19,21 @@ COMPOSER_ALLOW_SUPERUSER=1 composer install --no-interaction --optimize-autoload
echo "🗄️ Running migrations..."
php artisan migrate --force
echo "Running seeders..."
php artisan db:seed --force
echo "⚡ Optimizing application..."
php artisan optimize:clear
echo "🔄 Restarting PHP service..."
systemctl restart $PHP_VERSION-fpm
systemctl reload $PHP_VERSION-fpm
echo "🔁 Restarting Supervisor queue workers..."
supervisorctl stop all
supervisorctl reload
supervisorctl start all
php artisan queue:restart
supervisorctl reread
supervisorctl update
supervisorctl restart all
php artisan up
echo "🚀 Deployment completed successfully!"

File diff suppressed because one or more lines are too long

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

BIN
public/leaflet/layers.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 696 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 618 B

View File

@@ -2,30 +2,6 @@ import bootstrap from "bootstrap/dist/js/bootstrap";
window.bootstrap = bootstrap;
import "iconify-icon";
import "simplebar/dist/simplebar";
// import flatpickr from "flatpickr";
// import "flatpickr/dist/flatpickr.min.css";
// class InitDatePicker {
// constructor(selector = ".datepicker") {
// this.selector = selector;
// }
// init() {
// const elements = document.querySelectorAll(this.selector);
// if (elements.length === 0) return; // Skip if no elements found
// const today = new Date();
// const minYear = today.getFullYear() - 5;
// elements.forEach((element) => {
// flatpickr(element, {
// enableTime: false,
// dateFormat: "Y-m-d",
// minDate: `${minYear}-01-01`,
// maxDate: today,
// });
// });
// }
// }
class Components {
initBootstrapComponents() {
@@ -131,7 +107,6 @@ class FormValidation {
}
document.addEventListener("DOMContentLoaded", function (e) {
new Components().init(), new FormValidation().init();
// new InitDatePicker().init();
});
class ThemeLayout {
constructor() {

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