Compare commits

..

136 Commits

Author SHA1 Message Date
arifal
59cc102c5a create service count floor level and retributions 2025-06-18 18:44:30 +07:00
arifal
df70a47bd1 add build 2025-06-18 15:45:12 +07:00
arifal
e71dd7d213 count spatial plannings business and non business and create pbg task detail and add to syncrone daily 2025-06-18 13:45:35 +07:00
arifal hidayat
f2eb998ac5 build and add init spatial 2025-06-18 02:57:30 +07:00
arifal hidayat
fc54e20fa4 add spatial plannings retribution calculations 2025-06-18 02:54:41 +07:00
arifal
6946fa7074 update retribution calculation spatial plannings 2025-06-17 17:58:37 +07:00
arifal
236b6f9bfc add build frontend 2025-06-17 12:04:55 +07:00
arifal
285ff46c2b fix data setting get datatable using api token 2025-06-17 11:54:02 +07:00
arifal hidayat
a8b02afad9 add build production manifest 2025-06-14 04:22:57 +07:00
arifal hidayat
a0666e78d2 fix value dashboard verified component 2025-06-14 04:20:26 +07:00
arifal hidayat
799e409ce2 create build script 2025-06-14 02:48:00 +07:00
arifal hidayat
780ba60224 add sync to leader dashboard new from google spreadsheet 2025-06-14 02:15:49 +07:00
arifal
baed8cc487 fix 401 hit api 2025-06-13 20:43:16 +07:00
arifal
e17f5beaf0 production code 2025-06-13 13:36:27 +00:00
arifal
766e1a430c fix permision deploy 2025-06-13 20:08:14 +07:00
arifal
6677c320fc build and create deploy production 2025-06-13 19:53:23 +07:00
arifal hidayat
9437eb949f add docker 2025-06-06 22:42:41 +07:00
arifal
6f77120c33 backup database 2025-06-02 15:41:03 +07:00
arifal
f8d0573e5c remove description body response on datatable 2025-06-02 15:30:43 +07:00
arifal
ca74d0143f hot fix show all chart growth 2025-05-20 11:59:50 +07:00
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
@jamaludinarifrohman6661
fbfa2a37bb feature: set role previledge access 2025-03-07 14:39:46 +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
@jamaludinarifrohman6661
dceb46ab86 change-request: add custom geo layer 2025-03-06 16:50:13 +07:00
arifal
e0c35b8897 fix search filter on page big data resume 2025-03-06 14:39:36 +07:00
arifal
22ee7502ad Merge remote-tracking branch 'origin/feature/chatbot-sidebar' into fix/sync-task-assignment 2025-03-06 11:45:34 +07:00
arifal
2f3bc172eb add search filter 2025-03-06 11:42:59 +07:00
@jamaludinarifrohman6661
bba932b2ba Merge remote-tracking branch 'origin/dev' into feature/chatbot-sidebar 2025-03-06 11:20:45 +07:00
@jamaludinarifrohman6661
3f5d0eb1cd fix: inserting chat history into the answer generation process 2025-03-06 11:06:45 +07:00
arifal
1f33d0de4e add sync task assignment pbg 2025-03-06 00:13:13 +07:00
arifal
86d694bcac add new menu chat bedas and view 2025-03-04 17:56:30 +07:00
arifal
cb5a3243fc Merge remote-tracking branch 'origin/feature/chatbot-sidebar' into dev 2025-03-04 17:32:37 +07:00
@jamaludinarifrohman6661
15210a56ee feature: chatbot pimpinan 2025-03-04 17:31:40 +07:00
arifal
a08f2cb2b7 fix optimizing deployment 2025-03-04 16:45:32 +07:00
arifal
632433c496 fix routing spatial-plannings 2025-03-04 16:23:00 +07:00
arifal
5b4780495e fix routing spatial-plannings 2025-03-04 16:17:47 +07:00
arifal
0a7012a57c fix tourisms routing 2025-03-04 16:13:17 +07:00
arifal
435a19346b fix route umkm 2025-03-04 16:05:21 +07:00
arifal
8fcf8859d6 hot fix advertisement route conflict 2025-03-04 15:58:30 +07:00
arifal
43a246d234 add permission deployment file 2025-03-04 08:49:51 +00:00
arifal
d6d0acf8fb hot fix conflict routing web and api advertisements 2025-03-04 15:46:35 +07:00
arifal
b4ec7a9d25 merge chatbot sidebar 2025-03-04 15:19:11 +07:00
arifal
5203babe11 Merge remote-tracking branch 'origin/feature/chatbot-sidebar' into dev 2025-03-04 15:15:32 +07:00
arifal
c0faafdbd7 hot fix add time midnight scheduler 2025-03-04 15:13:33 +07:00
arifal
c5e3fdd915 create file automation deployment using sh 2025-03-04 15:05:13 +07:00
@jamaludinarifrohman6661
572b86299c add:setting main chatbot
fix:chatbot ui
2025-03-04 14:46:29 +07:00
arifal
cdd84d02da fix parsing separator 2025-03-04 14:30:41 +07:00
arifal
ee1a395c75 add per page 50 and add some column onn laporan pimpinan 2025-03-04 10:41:52 +07:00
arifal
3bfcaddba4 fix queue execute scraping syncronize simbg add new column to resume 2025-03-03 22:55:57 +07:00
arifal
9ea7e96af1 add vite and merge chatbot jamal 2025-02-28 18:39:23 +07:00
arifal
e0d11af7d2 Merge remote-tracking branch 'origin/feature/chatbot' into dev 2025-02-28 18:14:29 +07:00
@jamaludinarifrohman6661
fefef609ac feature: chatbot 2025-02-28 17:53:16 +07:00
arifal
f5790cda94 fix filter year dashboard 2025-02-28 15:46:31 +07:00
arifal
f3db3783f9 deployed 2025-02-28 2025-02-28 04:49:28 +00:00
arifal
101e76c0fa add js to vite 2025-02-28 11:45:55 +07:00
arifal
4cc698a623 fix handle disable button when upload business industries 2025-02-28 10:37:41 +07:00
arifal
544ad1db46 fix upload business and industry with chunk 2025-02-28 00:35:09 +07:00
arifal
30ca819aa1 fix color on maps 2025-02-27 20:14:37 +07:00
arifal
b0bab784d1 partial update add page laporan pimpinan and fix upload big data excel pdam 2025-02-27 19:23:06 +07:00
arifal
01fda22c89 partial update add loading on maps and add color for zone type maps 2025-02-26 23:52:48 +07:00
arifal
de300c2c32 fix dashboard style and resume bigdata 2025-02-26 21:52:23 +07:00
arifal
7f8a2e4936 Merge branch 'feature/dashboard-pbg' into dev 2025-02-25 11:34:08 +07:00
@jamaludinarifrohman6661
38948b6633 bug-fix: map tourisms 2025-02-25 11:32:39 +07:00
arifal
aa9943ba45 hot fix vite config js resources 2025-02-25 04:18:15 +00:00
arifal
9e55ea0dbb fix change api route data settings 2025-02-25 10:41:59 +07:00
546 changed files with 308946 additions and 9136 deletions

0
.editorconfig Executable file → Normal file
View File

3
.env.example Executable file → Normal file
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"

76
.env.local.backup Normal file
View File

@@ -0,0 +1,76 @@
APP_NAME=SIBEDAS-PBG
APP_ENV=local
APP_KEY=base64:xqCpwixWKqgu1Ca22gFizoOt44p7h+cgTOKuhS/P0Jw=
APP_DEBUG=true
APP_TIMEZONE=Asia/Jakarta
APP_URL=http://localhost:8000
API_URL=http://localhost:8000
APP_LOCALE=en
APP_FALLBACK_LOCALE=en
APP_FAKER_LOCALE=en_US
APP_MAINTENANCE_DRIVER=file
# APP_MAINTENANCE_STORE=database
PHP_CLI_SERVER_WORKERS=4
BCRYPT_ROUNDS=12
LOG_CHANNEL=stack
LOG_STACK=single
LOG_DEPRECATIONS_CHANNEL=null
LOG_LEVEL=debug
DB_CONNECTION=mariadb
DB_HOST=db
DB_PORT=3306
DB_DATABASE=sibedas_db
DB_USERNAME=root
DB_PASSWORD=root
SESSION_DRIVER=database
SESSION_LIFETIME=120
SESSION_ENCRYPT=false
SESSION_PATH=/
SESSION_DOMAIN=null
BROADCAST_CONNECTION=log
FILESYSTEM_DISK=local
QUEUE_CONNECTION=database
CACHE_STORE=database
CACHE_PREFIX=
MEMCACHED_HOST=127.0.0.1
REDIS_CLIENT=phpredis
REDIS_HOST=127.0.0.1
REDIS_PASSWORD=null
REDIS_PORT=6379
MAIL_MAILER=log
MAIL_HOST=127.0.0.1
MAIL_PORT=2525
MAIL_USERNAME=null
MAIL_PASSWORD=null
MAIL_ENCRYPTION=null
MAIL_FROM_ADDRESS="hello@example.com"
MAIL_FROM_NAME="${APP_NAME}"
AWS_ACCESS_KEY_ID=
AWS_SECRET_ACCESS_KEY=
AWS_DEFAULT_REGION=us-east-1
AWS_BUCKET=
AWS_USE_PATH_STYLE_ENDPOINT=false
VITE_APP_NAME="${APP_NAME}"
SIMBG_HOST="https://simbg.pu.go.id/"
SIMBG_EMAIL="dputr@bandungkab.go.id"
SIMBG_PASSWORD="Simbg123"
API_KEY_GOOGLE="AIzaSyBxfEShFkKmykkc7RJR3lVzkQ_xGHK3qr0"
SPREAD_SHEET_ID="1QoXzuLdEX3MK70Yrfigz0Qj5rAt4T819jX85vubBNdY"
OPENAI_API_KEY="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"

0
.gitattributes vendored Executable file → Normal file
View File

0
.gitignore vendored Executable file → Normal file
View File

View File

@@ -0,0 +1,42 @@
no,pemohon,alamat,activities,luas_lahan,bcr_kawasan,area,no_tapak,no_skkl,no_ukl,fungsi_bangunan,sub_fungsi_bangunan,jumlah_lantai
01/222,PT CIPTA INDAH PERTIWI No Telpon : 082217633434,Jl Salam No 51 Desa/Kel. Cihapit Kec. Bandung wetan Kota Bandung,PERUMAHAN LA LA TOWN,16629,0.2449,4072.4421,648.11./222 - SP /TR 07 Januari 2025;644.2./207 - SP /TR 02 Januari 2025,500.10.29.15/631-REKTEK/TR Tanggal 14 Februari 2023;500.10.29.15/2837-REKTEK/Bid. Taru Tanggal 25 Juli 2024,14022310313204030 Tanggal 14 Februari 2023;500.10.29.7/Kep.618-DLH/2024 Tanggal 13 Desember 2024;161023087545 Tanggal 16 Oktober2023,Fungsi Hunian,Fungsi Hunian,1
03/481,MUHAMAD GUNTUR JULIADI No Telpon : 081223334486,Cangkuang Residence RT 004/003 Ds Cangkuang Wetan Kec. Dayeuhkolot Kab. Bandung,PERUMAHAN CANGKUANG RESIDENCE 2,2360,0.5924,1398.064,648.11./481 - SP /TR 15 Januari 2025;647./226 - SP /TR 07 Januari 2025;647/225 - SP /TR 07 Januari 2025;644/221 - SP /TR 07 Januari 2025;645.4/557 - SP /TR 20 Januari 2025,500.10.29.15/2894-REKTEK/Bid. Taru Tanggal 08 Agustus 2024;400.7.22/4927-KRK/04/Bid.Taru Tanggal 06 Desember 2024;500.10.29.15/2619-REKTEK/Bid. Taru Tanggal 10 Juli 2024;500.10.29.15/4155-REKTEK/Bid. Taru Tanggal 18 Nopember 2024;503/123/III-DPMPTSP/2020 Tanggal 24 MAret 2020,167240099471 Tanggal 16 Juli 2024;9120111161314 Tanggal 11 Nopember 2019;8120312190151 Tanggal 04 Desember 2023;500.10.29.7/Kep.614-DLH/2024 Tanggal 20 Nopember 2024;2910240290118 Tanggal 29 Oktober 2024;8120001992981 Tanggal 12 Juli 2024;SK.294/Menlhk/Setjen/PLA.4/5/2021 Tanggal 31 Mei 2021,Fungsi Hunian,Fungsi Hunian,1
08/480,PT SURYA KHARISMA PARAHYANGAN No Telpon : 081394461006 ,Jalan Cibaligo No 48 Desa /Kel. Cigugur tengah Kec. Cimahi tengah kota Cimahi ,PERUMAHAN PARAHYANGAN GARDEN CITY,116360,0.5164,60088.304,648.11./480 - SP /TR 15 Januari 2025,500.10.29.15/603-REKTEK/TR Tanggal 05 Desember 2023,1810220245722 Tanggal 18 Oktober 2022;500.10.29.7/Kep.632-DLH/2024 Tanggal 24 Desember 2024,Fungsi Hunian,Fungsi Hunian,2
09/223,PT CLARICHEM INDONESIA No Telpon : 081315399694,Kawasan pergudangan taman tekno sektor XI blok L2 No 30 Ds/Kel. Setu Kec. Setu kota Tangerag Banten ,PERGUDANGAN DAN PENYIMPANAN,1586,0.7017,1112.8962,644./223 - SP /TR 07 Januari 2025,400.7.22/4427-KRK/03/Bid.Taru Tanggal 06 Desember 2024,9120008832767 Tanggal 26 Nopember 2024,Usaha Besar (Non-Mikro),Fungsi Usaha,1
10/657,PT HALKA GITA No Telpon : 0816734374,Jl Raya Majalaya KM 2 RT 02/09 Desa Hegarmanah Kec. Cikancung Kab. Bandung,REVISI 1 KOMPLEK PERGUDANGAN,19100,0.699,13350.9,644./657 - SP /TR 23 Januari 2025,500.10.29.15/6750-REKTEK/TR Tanggal 21 Desember 2023,9120300510839 Tanggal 16 Desember 2023;500.10.29.7/Kep.609-DLH/2024 Tanggal 12 Nopember 2024,Usaha Besar (Non-Mikro),Fungsi Usaha,2
11/658,PT SURYA TIRTA KENCANA No Telpon : 08986155493,Kutawaringin Industrial Park Kav. 276-277 Desa Jelegong Kec. Kutawaringin Kab. Bandung,PERGUDANGAN DAN PENYIMPANAN BAHAN KIMIA,3932,0.6995,2750.434,644./658 - SP /TR 23 Januari 2025;640/540 - SP /TR 20 Januari 2025,10112410113204010 Tanggal 10 Nopember 2024;591.4/031/IX-DPMPTSP/2020 Tanggal 03 Sseptember 2020,8120017120594 Tanggal 31 Agustus 2018;600.4.5/056/6838-Ktr/TL Tanggal 24 Desember 2024;0220305221438 Tanggal 20 Nopember 2021;500.10.29.7/4295/TL Tanggal 21 September 2024,Usaha Besar (Non-Mikro),Fungsi Usaha,1
13 / 550,PT BERKAH SEPUH JAYA No Telpon : 082118781624,Ruko komplek dewaadru blok R3 RT 005 ds/kec. Bojongsoang kab. Bandung,REVISI 1 PERUMAHAN VILLA CEMARA ASRI,17379,0.5476,9516.7404,648.11/550 - SP/TR 20 Januari 2025,150223101113204049 Tanggal 15 Februari 2023,1233000451657 Tanggal 5 Mei 2023;500.10.29.7/kep.392-DLH/2025 Tgl. 2 Januari 2025,Fungsi Hunian,Fungsi Hunian,2
14 / 655,PT RISKI ANUGERAH SEDJAHTERA No Telpon : 082118781624,Griya permata asri blok C2 No 18 Ds Lengkong Kec. Bojongsoang Kab. Bandung,REVISI 1 PERUMAHAN TAMAN KATAPANG INDAH,28425,0.6532,18567.21,648.11 /655 - SP /TR 23 Januari 2025,500.10.29.15/2333-REKTEK/TR Tanggal 22 Mei 2024;500.10.29.15/3811-REKTEK/Bid. Taru Tanggal 10 Oktober 2024,1205000302875 Tanggal 02 April 2024;500.10.29.7/Kep.408-DLH/2025 Tanggal 10 Januari 2025,Fungsi Hunian,Fungsi Hunian,2
15 / 551,PT BUMI SUWARNA SEJAHTERA No Telpon : 082118781624,Jl Ciwastra no 73 Kel. Mekarmulya kec. Rancasari kota bandung,REVISI 1 PERUMAHAN BUMI KARA RESIDENCE,29711,0.5424,16115.2464,648.11/551-SP/TR 20 Januari 2025,500.10.29.15/6097-REKTEK/TR Tanggal 27 Nopember 2023,1311230078306 Tgl 13 Nopember 2023;500.10.29.7/Kep.493-DLH/2024 Tanggal 20 Maret 2024,Fungsi Hunian,Fungsi Hunian,2
16 / 656,PT AMBER HASYA No Telpon : 081312411661,Jl Sarijadi raya No 111 Kel. Sarijadi Kec. Sukasarii kota bandung,REVISI 1 PERUMAHAN GREEN HARMONI RESIDENCE ,39520,0.2726,10773.152,648.11/656-SP/TR 23 Januari 2025,500.10.29.15/2732-REKTEK/Bid. Taru Tanggal 19 Juli 2024,9120004882226 Tgl 22 Agustus 2019;500.10.29.7/Kep.617-DLH/2024 Tanggal 4 Desember 2024,Fungsi Hunian,Fungsi Hunian,2
17 / 224,PT KARYA UTAMA SEJATI JAYA No Telpon : 081320772222,Kp. Andir DS/Kel. Manggahang Kec. Baleendah Kab. Bandung,PERUMAHAN GRAND CIPARAY RESIDENCE,12045,0.5945,7160.7525,648.11/224-SP/TR 07 Januari 2025;644/822-SP/TR 13 Februari 2025;640/524-SP/TR 17 Januari 2025;642/763-SP/TR 11 Februari 2025,500/5300-PERTEKTR/2022/TR Tanggal 04 Agustus 2022;400.7.22/4872-KRK/25/Bid.TR Tanggal 24 Desember 2024;Pu.650/7580-REKTEK/TR Tanggal 20 Desember 2022;01112410113204120 Tanggal 1 November 2024,1801220061544 Tgl 05 September 2022;600.4.5/052/1722-Ktr/TL Tanggal 20 Mei 2024;9120401971173 Tgl 11 Desember 2024;1406220076826 Tgl 15 November 2022;8120103802893 Tgl 29 Agustus 2018,Fungsi Hunian,Fungsi Hunian,2
21 / 688,PT PRAKARSA FAJAR PROPERTINDO No Telpon : 082315094712,Jl. Otto Iskandardinata No 429 Kel. Pungkur Kec. Regol Kota Bandung,PERUMAHAN ALAM BUMI CIPARAY,17417,0.6793,11831.3681,648.11/688-SP/TR 03 Februari 2025,500.10.29.15/1075-REKTEK/TR Tanggal 04 Maret 2024,9120007841259 Tgl 15 Agustus 2019;500.10.29.7/Kep.405-DLH/2025 Tanggal 06 Januari 2025,Fungsi Hunian,Fungsi Hunian,2
22 / 767,PT CITRA SENTOSA JAYATAMA No Telpon : 087825393706,Jl. Nyengseret No 29 RT 01 Kel. Pelindung hewaqn Kota Bandung,PERUMAHAN CITRA ASRI RESIDENCE,28900,0.692,19998.8,648.11/767-SP/TR 12 Februari 2025,500.10.29.15/2617-REKTEK/Bid. Taru Tanggal 10 Juli 2024,9120107971097 Tgl 19 September 2019;500.10.29.7/Kep.612-DLH/2024 Tanggal 18 November 2024,Fungsi Hunian,Fungsi Hunian,2
23/ 641,PT PESONA MITRA KEMBAR MAS No Telpon : 081220763283,Jl Kembar mas IV No 2A RT 05/09 Kel. Pasirluyu Kec. Regol Kota Bandung,REVISI 5 PERUMAHAN PODOMORO PARK,1160011,0.6691,776163.3601,648.11/641- SP/TR 22 Januari 2025,591/057-DPMPTSP/2017 Tanggal 28 Desember 2017,650/Kep.628-DLH/2018 Tanggal 30 Nopember 2018,Fungsi Hunian,Fungsi Hunian,2
24 / 659,PT PAVITRA PARA ARTHA No Telpon : 081809063866,Jl . Kubang Beureum No 39 RT 007 / 011 Kelurahan Sekejati Kecamatan Buahbatu,REVISI 4 PERUMAHAN PRIVATE VILLAGE,88245,0.5819,51349.7655,648.11/659 - SP/TR 23 Januari 2025;645/932 - SP/TR 21 Februari 2025;645/552-SP/TR 20 Januari 2025;647/640-SP/TR 22 Januari 2025;647/930-SP/TR 21 Februari 2025,591.4/001-BPMP/2014 Tanggal 06 Januari 2014;591.4/031-DPMPTSP/2019 Tanggal 10 Juli 2019;503/104/XII-DPMPTSP/2019- Tgl 20 Desember 2019;400.1.22/4521-KRK/15/Bid.Taru Tgl 16 Desember 2024;650/2597-KRTR/2021/TR Tgl 9 Desember 2021;500.10.29.15/2839-REKTEK/Bid.TAru Tgl 2 Agustus 2024,500.10.29.6/4898/TL Tanggal 08 Nopember 2023;667/2995/TL Tanggal 11 Agustus 2020;9120000431996 Tanggal 20 Oktober 2021;500.10.29.7/Kep.629-DLH/2024;9120605793306 Tanggal 9 Mei 2023;1601240112040181 Tanggal 16 Januari 2024;8120215192631 Tanggal 3 Januari 2022;34/LH.01.06.05/DLH Tanggal 3 Januari 2025;9120101841825 Tanggal 18 Oktober 2023,Fungsi Hunian,Fungsi Hunian,2
29 / 931,PT KARYA HAFANA INTAN MANDIRI No Telpon : 082120002925 ,Kp./Desa Ciluluk Kecamatan Cikancung Kabupaten Bandung,PERUMAHAN GRIYA CIHANYIR PERMAI,24432.33,0.5945,14525.02019,648.11/931 - SP/TR 21 Februari 2025,400.7.22/4840-KRK/21/Bid.Taru Tgl. 18 Desember 2024,2908210007625 Tanggal 06 Mei 2024;500.10.29.7/Kep.414-DLH/2025 Tanggal 30 Januari 2025,Fungsi Hunian,Fungsi Hunian,2
30 / 933,PT ARUM JAYA PROPERTI No Telpon : 085100942672,Perumahan Banyu Arum Residence Blok A Kp. Tegal Tengah RT 003/013 Desa Cangkuang Kec. Rancaekek,REVISI 1 PERUMAHAN BUMI ARUM REGENCY,58899,0.4838,28495.3362,648.11/933 - SP/PR 21 FEBRUARI 2025,591.4/026-DPMPTSP/2018 Tgl 24 September 2018,667/7210/TL Tanggal 16 Nopember 2018;500.10.29.6/Kep.420-DLH/2025 Tanmggal 3 Februari 2025,Fungsi Hunian,Fungsi Hunian,2
31 / 762,SANDY SALMAN No Telpon : 082118781624,Jl Kembar VIII No 26 RT 005/010 Kel Cigereleng Kec. Regol Kota Bandung 40253,REVISI 1 PERUMAHAN D HEUVEL WIWAHA PADASUKA,3095,0.4295,1329.3025,648.11/ 762 - SP / PR 11 Februari 2025;648/523-SP/TR 17 Januari 2025;647/1140-SP/TR 27 Februari 2025;647/934-SP/TR 21 Februari 2025;647/1233-SP/TR 06 Maret 2025,"650/5689-PETEKTR/2022/TR Tanggal 30 Agustus 2022;650/2748-KRTR/2021/TR Tgl 21 Desember 2021;593.SK.93-BKPMD/90 Tanggal 11 April 1990;593/SK.225-BKPMD/1991 Tanggal 28 Juni 1991;591,4/009-BPMP/2014 Tanggal 27 Maret 2014;500.10.29.15/711-REKTEK/TR Tanggal 15 Februari 2024;500.10.29.15/2877-REKTEK/Bid.Taru Tanggal 19 Agustus 2024 ",LH.01.04/5866-SPPL/TL Tanggal 27 Desember 2022;1402220064386 Tanggal 04 Februari 2022;500.10.29.7/Kep.593-DLH/2024 Tanggal 27 September 2024;667/3257/BPLH Tanggal 06 Oktober 2014;2711230388253 Tanggal 27 Nopember 2023;500.10.29.7/Kep.630-DLH/2024 Tanggal 20 Desember 2024;9120312050674 Tanggal 07 Oktober 2019;500.10.29.7/Kep.426-DLH/2025 Tanggal 14 Februari 2025,Fungsi Hunian,Fungsi Hunian,1
36/ 1141,HANDRIAWAN No Telpon : 081313350382,Jalan Taman Holis Indah E-5 No 4-5 RT 03/06 Ds/Kel. Cigondewah Kec. Bandung kulon. Kota Bandung,TOKO DAN GUDANG,2025,0.7848,1589.22,647/1141-SP/TR 27 Februari 2025;647/1211-SP/TR 04 Maret 2025;648.2/1091-SP/TR 25 Februari 2025,400.7.22/559-KRK/14/Bid.Taru Tanggal 17 Januari 2025;400.7.22/859-KRK/38/Bid.Taru Tanggal 17 Februari 2025;500.10.29.15/4064 - REKTEK/Bid.Taru Tanggal 25 Nopember 2024,1401250067962 Tanggal 14 Januari 2025;1812240057832 Tanggal 18 Desember 2024;1611210013009 Tanggal 16 Nopember 2021,Usaha Besar (Non-Mikro),Fungsi Usaha,1
39/ 1232,JOHANSJAH SUGIANTO No Telpon : 081314974495,Jalan Kepodang VI/6 blok k2 Rengas Kec. Ciputat timur kota Tangerang selatan,TOKO,2490,21.9,54531,644.2/1232-SP/TR 06 Maret 2025;644.2/1234-SP/TR 06 Maret 2025,400.7.22/1089 - KRK/45//Bid.Taru Tanggal 24 Februari 2025;503/0017-PKKPRNB/DPMPTSP/II/2025 Tanggal 12 Februari 2025,3101250002573 Tanggal 31 Januari 2025;2107230112343 Tanggal 21 Juli 2023,Tidak Diketahui,Tidak Diketahui,3
41 / 1090,TIM AD HOC PERUMAHAN SUKAWANGI RESIDENCE No Telpon : 08112255770,Kp. Cihalimun RT 02/04 Ds. Cibeureum Kec. Kertasari Kab. Bandung,PERUMAHAN SUKAWANGI RESIDENCE,,1,,648.11/ 1090 - SP / PR 25 Februari 2025,,,Fungsi Hunian,Fungsi Hunian,2
42 / 1298,PT TIGA REKAN INDONESIA No Telpon : 08122444717,Jl Gradiul No 40 RT 04/07 Kel. Rancaekek Kencana Kec. Rancaekek Kab. Bandung,PERUMAHAN GREEN HILL VILLAGE,16548,0.5917,9791.4516,648.11/1298 - SP/TR 17 Maret 2025,50.10.29.15/2742-REKTEK/Bid. Taru Tanggal 24 Juli 2024,2505240130006 Tanggal 25 Mei 2024;600.4.5/061/832-Ktr/Bid. TL/2025 Tgl. 19 Februari 2025,Fungsi Hunian,Fungsi Hunian,2
43 / 1322,PT UNILOA ARDIYANTO INVESTAMA No Telpon : 081220180480,Jl Raya Ebah 103 Desa Sukamantri Kecamatan Paseh Kab. Bandung,PERUMAHAN MARISON CIPAKU,19209,0.6146,11805.8514,648.11/1322 - SP/TR 18 Maret 2025,24042410313204051 Tanggal 24 JApril 2024,0238010110358 Tanggal 11 Januari 2024;500.10.29.7/Kep. 451-DLH/2025 Tgl. 13 Maret 2025,Fungsi Hunian,Fungsi Hunian,2
44 / 1323,PT RADINAKA KRAMAT ABADI No Telpon : 082118781624,Jl. Sukamukti RT 01/06 Desa Sukamukti Kec. Katapang Kab. Bandung,PERUMAHAN GAHARU PALEDANG RESIDENCE,14665,0.68003,9972.63995,648.11/1323 - SP/TR 18 Maret 2025,02032510213204087 Tanggal 02 Maret 2025,0238010110358 Tanggal 11 Januari 2024;600.4.5/064/1165-Ktr/Bid. TL/2025 Tgl. 12 Maret 2025,Fungsi Hunian,Fungsi Hunian,2
45 / 1361,PT SANGKURIANG KRAMAT ABADI No Telpon : 082118781624,Kampung rancakasiat Desa Rancamulya Kec. Pameungpeuk Kab. Bandung,PERUMAHAN PONDOK ASRI SUKAMUKTI,20451,0.6806,13918.9506,648.11/1361 - SP/TR 24 Maret 2025,500.10.29.15/3451-REKTEK/Bid.Taru Tanggal 26 September 2024,0811230037204 Tanggal 08 Nopember 2023;500.10.29.7/Kep.460-DLH/2025 Tgl. 21 Maret 2025,Fungsi Hunian,Fungsi Hunian,2
46 / 1360,PT AUF ABDURACCHMAN JAYA No Telpon : 082118781624,Jl. Rancabungur rancakasiat Desa Malakasari Kec. Baleendah Kab. Bandung,PERUMAHAN BUMI SHANGRILA RESIDENCE,12846,0.6412,8236.8552,648.11/1360 - SP/TR 24 Maret 2025,400.7.22/093/1390-KRK/Bid.Taru Tanggal 17 Maret 2025,0603250028082 Tanggal 06 Maret 2025;600.4.5/072/1270-Ktr/Bid.TL/2025 Tgl. 21 Maret 2025,Fungsi Hunian,Fungsi Hunian,2
47 / 1142,ANTO DWI HARTANTO No Telpon : 082126215611,Jl. Elang V No 8 RT 08/01 Kel. Garuda Kec. Andir Kota Bandung,PERGUDANGAN DAN PENYIMPANAN,1307,0.5616,734.0112,647/1142 - SP/TR 27 Februari 2025;648.11/823 - SP/TR 13 Februari 2025;644.2/1389 - SP/TR 26 Maret 2025;644.2/1388 - SP/TR 26 Maret 2025,500.10.29.15/3827-REKTEK/Bid.Taru Tanggal 17 Oktober 2024;500.10.29.15/3944-REKTEK/Bid.Taru Tanggal 28 Oktober 2024;503/0072-DPMPTSP/XI/2023 Tanggal 29 November 2023;400.7.22/1046-KRK/Bid.Taru Tanggal 21 Februari 2025,2009240075774 Tanggal 20 September 2024 2025;2009240075774 Tanggal 20 September 2025;500.10.29.7/Hep-461-DLH/2025 Tanggal 21 Maret 2025;0298000921888 Tanggal 24 Januari 2022,Usaha Besar (Non-Mikro),Fungsi Usaha,1
51 / 1161,PT INGRIA PRATAMA CAPITALINDO Tbk No Telpon : 087722361043,Ruko Pondok Cabe Mutiara Jl Pondok cabe No 27 Kel. Pamulang Kec. Pamulang Kota Tangerang Selatan,REVISI 2 PERUMAHAN BUKIT ESMA CICALENGKA 2 ,74300,0.6292,46749.56,648.11/1161 - SP/TR 28 Februari 2025,50.10.29.15/2927-REKTEK/Bid. Taru Tanggal 14 Agustus 2024,591.4/005/IX-DPMPTSP/2019 Tanggal 09 September 2019;500.10.29.7/Kep.613-DLH/2024 Tgl. 18 November 2025,Fungsi Hunian,Fungsi Hunian,2
52 / 1441 ,PT ABADI MUKTI KIRANA No Telpon : 087821848944,Jl Terusan jamika No 88 Kel. Jamika Kec. Bojongloa kaler Kota Bandung, PERUMAHAN KOTA BARU ARJASARI,222816,1,222816,648.11/1441 - SP/TR 11 April 2025,400.7.28/1710/TR Tanggal 23 April 2024,9120108201236 Tanggal 13 Februari 2019;500.10.29.7/Kep.419-DLH/2025 Tgl. 03 Februari 2025,Fungsi Hunian,Fungsi Hunian,2
53 / 1566,PT MAKMUR INDAH DAMAI No Telpon : 081394722234,Jl. Podomoro Boulevard utara I Desa Lengkong Kec. Bojongsoang Kab. Bandung,PERUMAHAN BAROS INDAH RESIDENCE,17513,1,17513,647/1566 - SP/TR 25 April 2025,50.10.29.15/2507-REKTEK/Bid. Taru Tanggal 25 Juni 2024,2106240023693 Tanggal 21 Juni 2024;500.10.29.7/Kep.447-DLH/2024 Tgl. 10 Maret 2025,Fungsi Hunian,Fungsi Hunian,2
54 / 1343,PT KARYA BUMI BESTARI No Telpon : 08156080428,Kembar Mas IV No 2A RT 05/09 Kel. Pasirluyu Kec. Regol Kota Bandung,PERUMAHAN BESTARI MAS,26134,1,26134,648.11/1343 - SP/TR 20 Maret 2025;647/1565 - SP/TR 25 April 2025;648.1/1543 - SP/TR 17 April 2025,12042310213204004 Tanggal 12 April 2023;23122410113204057 Tanggal 23 Desember 2024;400.7.22/1047-KRK/42/Bid.Taru Tanggal 21 Februari 2025,1204230043635 Tanggal 12 April 2023;500.10.29.7/964/Bid. TL/2025 Tgl. 19 Februari 2025;9120304390956 Tanggal 05 Desember 2023;0307230050445 Tanggal 03 Juli 2023,Fungsi Hunian,Fungsi Hunian,2
57 / 1372,TENNI DIANA No Telpon : 082116106640,Cikaahuripan RT 002/005 Kec. Neglasari Kota Tangerang,PERADAGANGAN KHUSUS KARPET PERMADANI DAN PENUTUP DINDING DN LANTAI DI TOKO,1290,1,1290,644/1372 - SP/TR 26 Maret 2025;647/1557 - SP/TR 22 April 2025;640/1559 - SP/TR 22 April 2025;644/1371 - SP/TR 26 Maret 2025;644/1375 - SP/TR 26 Maret 2025;644/1373 - SP/TR 26 Maret 2025,500.10.29.15/4355-REKTEK/TR Tanggal 25 Agustus 2023;500.10.29.15/1073-REKTEK/TR Tanggal 04 Maret 2024;400.7.22/759-KRK/34/Bid.Taru Tanggal 11 Februari 2025;500.10.29.15/4654-REKTEK/Bid. Taru Tanggal 08 September 2023;500.10.29.15/4160-REKTEK/Bid. Taru Tanggal 15 Nopember 2024;500.10.29.15/2500-REKTEK/Bid. Taru Tanggal 19 Juni 2024,9120306652149 Tanggal 26 Juni 2019;0220107462528 Tanggal 08 September 2022;1283000240318 Tanggal 01 Februari 2021;600.4.5/071-KTR/Bid.TL/2025 Tgl. 05 Mei 2025;0220301251224 Tanggal 11 Agustus 2023;1263000210596 Tanggal 09 Februari 2021;1405240295325 5 Mei 2024,Tidak Diketahui,Tidak Diketahui,1
63 / 1567,Ir. BERSIH TARIGANT No Telpon : 081322777581,Jl Multatuli No 3 rt 001/001 Ds/Kel. Lebakgede Kec. Coblong Kota Bandung,PERUMAHAN TUSCANY HILL,23796,0.2428,5777.6688,648.11/1567 - SP/TR 25 April 2025,50.10.29.15/3829-REKTEK/Bid. Taru Tanggal 15 Oktober 2024,2007220014068 Tanggal 20 Juli 2025;500.10.29.7/Kep.429-DLH/2025 Tgl. 10 Maret 2025,Fungsi Hunian,Fungsi Hunian,2
64 / 1682,PT CIPTA BERKAT PROPERTI No Telpon : 081910661980,Ruko Matahari Cigado No 25 Jalan Anggadireja Kel. Baleendah Kec. Baleendah Kab. Bandung,PERUMAHAN GARDEN VIEW CICALENGKA,45666,1,45666,648.11/1682 - SP/TR 06 Mei 2025,50.10.29.15/3156-REKTEK/Bid. Taru Tanggal 05 September 2024,2310210017936 Tanggal 23 Oktober 2021;500.10.29.7/Kep.477-DLH/2025 Tgl. 17 April 2025,Fungsi Hunian,Fungsi Hunian,2
64 / 1682,PT CIPTA BERKAT PROPERTI No Telpon : 081910661980,Ruko Matahari Cigado No 25 Jalan Anggadireja Kel. Baleendah Kec. Baleendah Kab. Bandung,C. KWT PERUMAHAN,0,1,0,,,,Fungsi Hunian,Fungsi Hunian,1
65 / 1644,PT ARGUNA JAYA PROPERTY No Telpon : 081214211164,Jl Pidada IV/4 Denpasar BR/Link Sedana metra Kel. Ubung Kec. Denpasar Utara Kota Denpasar,REVISI 1 PERUMAHAN ARGUNA SINDANGPANON,8553,0.53,4533.09,648.11/1644 - SP/TR 29 April 2025;644/1558 - SP/TR 22 April 2025,503/009/II-DPMPTSP/2020 Tanggal 25 Februari 2020;50.10.29.15/4063-REKTEK/Bid. Taru Tanggal 25 Nopember 2025,9120004890734 Tanggal 03 Agustus 2019;667/2081/TL Tgl. 08 Juni 2020;0609240042720001 Tanggal 06 September 2024,Fungsi Hunian,Fungsi Hunian,1
67/ 1370,NENENG FATIMAH No Telpon : 08977980040,Jalan Batu Indah I No 26 RT 002/003 Kel. Batununggal Kec. Bandung Kidul Kota Bandung,PERGUDANGAN DAN PENYIMPANAN,2034,1,2034,644/1370 - SP/TR 26 Maret 2025,50.10.29.15/3340-REKTEK/Bid. Taru Tanggal 18 September 2025,1009240038601 Tanggal 10 September 2024,Usaha Besar (Non-Mikro),Fungsi Usaha,1
68/ 1374,LILI JOJON No Telpon : 082219855556,Kp. Cibisoro RT 004/008 Desa Nanjung Kec. Mrgaasih Kab. Bandung,PERGUDANGAN DAN PENYIMPANAN,1654,1,1654,644/1374 - SP/TR 26 Maret 2025;644.2/1683 - SP/TR 06 Mei 2025;645/1730 - SP/TR 07 Mei 2025,50.10.29.15/3210-REKTEK/Bid. Taru Tanggal 10 September 2024;400.7.22/1254-KRK/58/Bid. Taru Tanggal 10 Maret 2025;50.10.29.15/3443-REKTEK/Bid. Taru Tanggal 26 September 2024,1220000361065 Tanggal 16 Maret 2021;1712240056863 Tanggal 17 Desember 2024;0103230081544 Tanggal 01 Maret 2023;600.4.5/071/1503-Ktr/Bid. TL/2025 Tanggal 17 April 2025,Usaha Besar (Non-Mikro),Fungsi Usaha,1
71/ 1845,PT SANGKURIANG KRAMAT ABADI No Telpon : 082116602145,Kp. Rancakasiat Desa Rancamulya Kec. Pameungpeuk Kab. Bandung,PERUMAHAN CLUSTER GAHARU EMERALD,19889,1,19889,648.11 /1845 - SP/TR 19 Mei 2025,400.7.22/1526-KRK/96/Bid. Taru Tanggal 22 April 2025,0811230037204 Tanggal 08 Nopember 2023;500.10.29.7/Kep. 489-DLH/2025 Tanggal 15 Mei 2025,Fungsi Hunian,Fungsi Hunian,2
72/ 1731,PT MARGA TIRTA KENCANA No Telpon : 082130000146,Jlan BKR Lingkar selatan No 140 Kota Bandung,PERUMAHAN TAMAN CIBADUYUT INDAH 2 DAN 3,205344,1,205344,648.11 /1731 - SP/TR 07 Mei 2025;648.11 /1946 - SP/TR 22 Mei 2025;643 /1881 - SP/TR 20 Mei 2025;644 /1684 - SP/TR 06 Mei 2025;648.12 /1825 - SP/TR 16 Mei 2025,591.4/002-BPMP/2010 Tanggal 10 Januari 2010;500.10.29.15/3108-REKTEK/Bid.taru Tanggal 29 Agustus 2024;500.10.29.15/3319-REKTEK/TR Tanggal 14 Juli 2023;12092410313204101 Tanggal 12 September 2024;400.7.22/1231-KRK/Bid.Taru Tanggal 06 Maret 2025,667/3803/DLH Tanggal 22 Desember 2016;9120204202309 Tanggal 20 Februari 2019;2002230028317 Tanggal 20 Februari 2023;600.4.5/073/1562-Ktr/Bid.TL/2025 Tanggal 23 April 2025;8120006931402 Tanggal 28 September 2022;12710006324580004 Tanggal 05 Maret 2025,Fungsi Hunian,Fungsi Hunian,2
77/ 1879,PT PUTRA RAHMAN PRADANA No Telpon : 081312214962,Perum Cemerlang Permai Blok C No 16 Kel. Sukakarya Kec. Warudoyongf Kota Sukabumi,REVISI 1 PERUMAHAN BUKIT PINUS BANIARAN,90711,1,90711,648.11 /1879 - SP/TR 20 Mei 2025,22122310313204009 Tanggal 22 Desember 2023,500.10.29.7/Kep.482-DLH/2025 Tanggal 24 April 2025,Fungsi Hunian,Fungsi Hunian,2
1 no pemohon alamat activities luas_lahan bcr_kawasan area no_tapak no_skkl no_ukl fungsi_bangunan sub_fungsi_bangunan jumlah_lantai
2 01/222 PT CIPTA INDAH PERTIWI No Telpon : 082217633434 Jl Salam No 51 Desa/Kel. Cihapit Kec. Bandung wetan Kota Bandung PERUMAHAN LA LA TOWN 16629 0.2449 4072.4421 648.11./222 - SP /TR 07 Januari 2025;644.2./207 - SP /TR 02 Januari 2025 500.10.29.15/631-REKTEK/TR Tanggal 14 Februari 2023;500.10.29.15/2837-REKTEK/Bid. Taru Tanggal 25 Juli 2024 14022310313204030 Tanggal 14 Februari 2023;500.10.29.7/Kep.618-DLH/2024 Tanggal 13 Desember 2024;161023087545 Tanggal 16 Oktober2023 Fungsi Hunian Fungsi Hunian 1
3 03/481 MUHAMAD GUNTUR JULIADI No Telpon : 081223334486 Cangkuang Residence RT 004/003 Ds Cangkuang Wetan Kec. Dayeuhkolot Kab. Bandung PERUMAHAN CANGKUANG RESIDENCE 2 2360 0.5924 1398.064 648.11./481 - SP /TR 15 Januari 2025;647./226 - SP /TR 07 Januari 2025;647/225 - SP /TR 07 Januari 2025;644/221 - SP /TR 07 Januari 2025;645.4/557 - SP /TR 20 Januari 2025 500.10.29.15/2894-REKTEK/Bid. Taru Tanggal 08 Agustus 2024;400.7.22/4927-KRK/04/Bid.Taru Tanggal 06 Desember 2024;500.10.29.15/2619-REKTEK/Bid. Taru Tanggal 10 Juli 2024;500.10.29.15/4155-REKTEK/Bid. Taru Tanggal 18 Nopember 2024;503/123/III-DPMPTSP/2020 Tanggal 24 MAret 2020 167240099471 Tanggal 16 Juli 2024;9120111161314 Tanggal 11 Nopember 2019;8120312190151 Tanggal 04 Desember 2023;500.10.29.7/Kep.614-DLH/2024 Tanggal 20 Nopember 2024;2910240290118 Tanggal 29 Oktober 2024;8120001992981 Tanggal 12 Juli 2024;SK.294/Menlhk/Setjen/PLA.4/5/2021 Tanggal 31 Mei 2021 Fungsi Hunian Fungsi Hunian 1
4 08/480 PT SURYA KHARISMA PARAHYANGAN No Telpon : 081394461006 Jalan Cibaligo No 48 Desa /Kel. Cigugur tengah Kec. Cimahi tengah kota Cimahi PERUMAHAN PARAHYANGAN GARDEN CITY 116360 0.5164 60088.304 648.11./480 - SP /TR 15 Januari 2025 500.10.29.15/603-REKTEK/TR Tanggal 05 Desember 2023 1810220245722 Tanggal 18 Oktober 2022;500.10.29.7/Kep.632-DLH/2024 Tanggal 24 Desember 2024 Fungsi Hunian Fungsi Hunian 2
5 09/223 PT CLARICHEM INDONESIA No Telpon : 081315399694 Kawasan pergudangan taman tekno sektor XI blok L2 No 30 Ds/Kel. Setu Kec. Setu kota Tangerag Banten PERGUDANGAN DAN PENYIMPANAN 1586 0.7017 1112.8962 644./223 - SP /TR 07 Januari 2025 400.7.22/4427-KRK/03/Bid.Taru Tanggal 06 Desember 2024 9120008832767 Tanggal 26 Nopember 2024 Usaha Besar (Non-Mikro) Fungsi Usaha 1
6 10/657 PT HALKA GITA No Telpon : 0816734374 Jl Raya Majalaya KM 2 RT 02/09 Desa Hegarmanah Kec. Cikancung Kab. Bandung REVISI 1 KOMPLEK PERGUDANGAN 19100 0.699 13350.9 644./657 - SP /TR 23 Januari 2025 500.10.29.15/6750-REKTEK/TR Tanggal 21 Desember 2023 9120300510839 Tanggal 16 Desember 2023;500.10.29.7/Kep.609-DLH/2024 Tanggal 12 Nopember 2024 Usaha Besar (Non-Mikro) Fungsi Usaha 2
7 11/658 PT SURYA TIRTA KENCANA No Telpon : 08986155493 Kutawaringin Industrial Park Kav. 276-277 Desa Jelegong Kec. Kutawaringin Kab. Bandung PERGUDANGAN DAN PENYIMPANAN BAHAN KIMIA 3932 0.6995 2750.434 644./658 - SP /TR 23 Januari 2025;640/540 - SP /TR 20 Januari 2025 10112410113204010 Tanggal 10 Nopember 2024;591.4/031/IX-DPMPTSP/2020 Tanggal 03 Sseptember 2020 8120017120594 Tanggal 31 Agustus 2018;600.4.5/056/6838-Ktr/TL Tanggal 24 Desember 2024;0220305221438 Tanggal 20 Nopember 2021;500.10.29.7/4295/TL Tanggal 21 September 2024 Usaha Besar (Non-Mikro) Fungsi Usaha 1
8 13 / 550 PT BERKAH SEPUH JAYA No Telpon : 082118781624 Ruko komplek dewaadru blok R3 RT 005 ds/kec. Bojongsoang kab. Bandung REVISI 1 PERUMAHAN VILLA CEMARA ASRI 17379 0.5476 9516.7404 648.11/550 - SP/TR 20 Januari 2025 150223101113204049 Tanggal 15 Februari 2023 1233000451657 Tanggal 5 Mei 2023;500.10.29.7/kep.392-DLH/2025 Tgl. 2 Januari 2025 Fungsi Hunian Fungsi Hunian 2
9 14 / 655 PT RISKI ANUGERAH SEDJAHTERA No Telpon : 082118781624 Griya permata asri blok C2 No 18 Ds Lengkong Kec. Bojongsoang Kab. Bandung REVISI 1 PERUMAHAN TAMAN KATAPANG INDAH 28425 0.6532 18567.21 648.11 /655 - SP /TR 23 Januari 2025 500.10.29.15/2333-REKTEK/TR Tanggal 22 Mei 2024;500.10.29.15/3811-REKTEK/Bid. Taru Tanggal 10 Oktober 2024 1205000302875 Tanggal 02 April 2024;500.10.29.7/Kep.408-DLH/2025 Tanggal 10 Januari 2025 Fungsi Hunian Fungsi Hunian 2
10 15 / 551 PT BUMI SUWARNA SEJAHTERA No Telpon : 082118781624 Jl Ciwastra no 73 Kel. Mekarmulya kec. Rancasari kota bandung REVISI 1 PERUMAHAN BUMI KARA RESIDENCE 29711 0.5424 16115.2464 648.11/551-SP/TR 20 Januari 2025 500.10.29.15/6097-REKTEK/TR Tanggal 27 Nopember 2023 1311230078306 Tgl 13 Nopember 2023;500.10.29.7/Kep.493-DLH/2024 Tanggal 20 Maret 2024 Fungsi Hunian Fungsi Hunian 2
11 16 / 656 PT AMBER HASYA No Telpon : 081312411661 Jl Sarijadi raya No 111 Kel. Sarijadi Kec. Sukasarii kota bandung REVISI 1 PERUMAHAN GREEN HARMONI RESIDENCE 39520 0.2726 10773.152 648.11/656-SP/TR 23 Januari 2025 500.10.29.15/2732-REKTEK/Bid. Taru Tanggal 19 Juli 2024 9120004882226 Tgl 22 Agustus 2019;500.10.29.7/Kep.617-DLH/2024 Tanggal 4 Desember 2024 Fungsi Hunian Fungsi Hunian 2
12 17 / 224 PT KARYA UTAMA SEJATI JAYA No Telpon : 081320772222 Kp. Andir DS/Kel. Manggahang Kec. Baleendah Kab. Bandung PERUMAHAN GRAND CIPARAY RESIDENCE 12045 0.5945 7160.7525 648.11/224-SP/TR 07 Januari 2025;644/822-SP/TR 13 Februari 2025;640/524-SP/TR 17 Januari 2025;642/763-SP/TR 11 Februari 2025 500/5300-PERTEKTR/2022/TR Tanggal 04 Agustus 2022;400.7.22/4872-KRK/25/Bid.TR Tanggal 24 Desember 2024;Pu.650/7580-REKTEK/TR Tanggal 20 Desember 2022;01112410113204120 Tanggal 1 November 2024 1801220061544 Tgl 05 September 2022;600.4.5/052/1722-Ktr/TL Tanggal 20 Mei 2024;9120401971173 Tgl 11 Desember 2024;1406220076826 Tgl 15 November 2022;8120103802893 Tgl 29 Agustus 2018 Fungsi Hunian Fungsi Hunian 2
13 21 / 688 PT PRAKARSA FAJAR PROPERTINDO No Telpon : 082315094712 Jl. Otto Iskandardinata No 429 Kel. Pungkur Kec. Regol Kota Bandung PERUMAHAN ALAM BUMI CIPARAY 17417 0.6793 11831.3681 648.11/688-SP/TR 03 Februari 2025 500.10.29.15/1075-REKTEK/TR Tanggal 04 Maret 2024 9120007841259 Tgl 15 Agustus 2019;500.10.29.7/Kep.405-DLH/2025 Tanggal 06 Januari 2025 Fungsi Hunian Fungsi Hunian 2
14 22 / 767 PT CITRA SENTOSA JAYATAMA No Telpon : 087825393706 Jl. Nyengseret No 29 RT 01 Kel. Pelindung hewaqn Kota Bandung PERUMAHAN CITRA ASRI RESIDENCE 28900 0.692 19998.8 648.11/767-SP/TR 12 Februari 2025 500.10.29.15/2617-REKTEK/Bid. Taru Tanggal 10 Juli 2024 9120107971097 Tgl 19 September 2019;500.10.29.7/Kep.612-DLH/2024 Tanggal 18 November 2024 Fungsi Hunian Fungsi Hunian 2
15 23/ 641 PT PESONA MITRA KEMBAR MAS No Telpon : 081220763283 Jl Kembar mas IV No 2A RT 05/09 Kel. Pasirluyu Kec. Regol Kota Bandung REVISI 5 PERUMAHAN PODOMORO PARK 1160011 0.6691 776163.3601 648.11/641- SP/TR 22 Januari 2025 591/057-DPMPTSP/2017 Tanggal 28 Desember 2017 650/Kep.628-DLH/2018 Tanggal 30 Nopember 2018 Fungsi Hunian Fungsi Hunian 2
16 24 / 659 PT PAVITRA PARA ARTHA No Telpon : 081809063866 Jl . Kubang Beureum No 39 RT 007 / 011 Kelurahan Sekejati Kecamatan Buahbatu REVISI 4 PERUMAHAN PRIVATE VILLAGE 88245 0.5819 51349.7655 648.11/659 - SP/TR 23 Januari 2025;645/932 - SP/TR 21 Februari 2025;645/552-SP/TR 20 Januari 2025;647/640-SP/TR 22 Januari 2025;647/930-SP/TR 21 Februari 2025 591.4/001-BPMP/2014 Tanggal 06 Januari 2014;591.4/031-DPMPTSP/2019 Tanggal 10 Juli 2019;503/104/XII-DPMPTSP/2019- Tgl 20 Desember 2019;400.1.22/4521-KRK/15/Bid.Taru Tgl 16 Desember 2024;650/2597-KRTR/2021/TR Tgl 9 Desember 2021;500.10.29.15/2839-REKTEK/Bid.TAru Tgl 2 Agustus 2024 500.10.29.6/4898/TL Tanggal 08 Nopember 2023;667/2995/TL Tanggal 11 Agustus 2020;9120000431996 Tanggal 20 Oktober 2021;500.10.29.7/Kep.629-DLH/2024;9120605793306 Tanggal 9 Mei 2023;1601240112040181 Tanggal 16 Januari 2024;8120215192631 Tanggal 3 Januari 2022;34/LH.01.06.05/DLH Tanggal 3 Januari 2025;9120101841825 Tanggal 18 Oktober 2023 Fungsi Hunian Fungsi Hunian 2
17 29 / 931 PT KARYA HAFANA INTAN MANDIRI No Telpon : 082120002925 Kp./Desa Ciluluk Kecamatan Cikancung Kabupaten Bandung PERUMAHAN GRIYA CIHANYIR PERMAI 24432.33 0.5945 14525.02019 648.11/931 - SP/TR 21 Februari 2025 400.7.22/4840-KRK/21/Bid.Taru Tgl. 18 Desember 2024 2908210007625 Tanggal 06 Mei 2024;500.10.29.7/Kep.414-DLH/2025 Tanggal 30 Januari 2025 Fungsi Hunian Fungsi Hunian 2
18 30 / 933 PT ARUM JAYA PROPERTI No Telpon : 085100942672 Perumahan Banyu Arum Residence Blok A Kp. Tegal Tengah RT 003/013 Desa Cangkuang Kec. Rancaekek REVISI 1 PERUMAHAN BUMI ARUM REGENCY 58899 0.4838 28495.3362 648.11/933 - SP/PR 21 FEBRUARI 2025 591.4/026-DPMPTSP/2018 Tgl 24 September 2018 667/7210/TL Tanggal 16 Nopember 2018;500.10.29.6/Kep.420-DLH/2025 Tanmggal 3 Februari 2025 Fungsi Hunian Fungsi Hunian 2
19 31 / 762 SANDY SALMAN No Telpon : 082118781624 Jl Kembar VIII No 26 RT 005/010 Kel Cigereleng Kec. Regol Kota Bandung 40253 REVISI 1 PERUMAHAN D HEUVEL WIWAHA PADASUKA 3095 0.4295 1329.3025 648.11/ 762 - SP / PR 11 Februari 2025;648/523-SP/TR 17 Januari 2025;647/1140-SP/TR 27 Februari 2025;647/934-SP/TR 21 Februari 2025;647/1233-SP/TR 06 Maret 2025 650/5689-PETEKTR/2022/TR Tanggal 30 Agustus 2022;650/2748-KRTR/2021/TR Tgl 21 Desember 2021;593.SK.93-BKPMD/90 Tanggal 11 April 1990;593/SK.225-BKPMD/1991 Tanggal 28 Juni 1991;591,4/009-BPMP/2014 Tanggal 27 Maret 2014;500.10.29.15/711-REKTEK/TR Tanggal 15 Februari 2024;500.10.29.15/2877-REKTEK/Bid.Taru Tanggal 19 Agustus 2024 LH.01.04/5866-SPPL/TL Tanggal 27 Desember 2022;1402220064386 Tanggal 04 Februari 2022;500.10.29.7/Kep.593-DLH/2024 Tanggal 27 September 2024;667/3257/BPLH Tanggal 06 Oktober 2014;2711230388253 Tanggal 27 Nopember 2023;500.10.29.7/Kep.630-DLH/2024 Tanggal 20 Desember 2024;9120312050674 Tanggal 07 Oktober 2019;500.10.29.7/Kep.426-DLH/2025 Tanggal 14 Februari 2025 Fungsi Hunian Fungsi Hunian 1
20 36/ 1141 HANDRIAWAN No Telpon : 081313350382 Jalan Taman Holis Indah E-5 No 4-5 RT 03/06 Ds/Kel. Cigondewah Kec. Bandung kulon. Kota Bandung TOKO DAN GUDANG 2025 0.7848 1589.22 647/1141-SP/TR 27 Februari 2025;647/1211-SP/TR 04 Maret 2025;648.2/1091-SP/TR 25 Februari 2025 400.7.22/559-KRK/14/Bid.Taru Tanggal 17 Januari 2025;400.7.22/859-KRK/38/Bid.Taru Tanggal 17 Februari 2025;500.10.29.15/4064 - REKTEK/Bid.Taru Tanggal 25 Nopember 2024 1401250067962 Tanggal 14 Januari 2025;1812240057832 Tanggal 18 Desember 2024;1611210013009 Tanggal 16 Nopember 2021 Usaha Besar (Non-Mikro) Fungsi Usaha 1
21 39/ 1232 JOHANSJAH SUGIANTO No Telpon : 081314974495 Jalan Kepodang VI/6 blok k2 Rengas Kec. Ciputat timur kota Tangerang selatan TOKO 2490 21.9 54531 644.2/1232-SP/TR 06 Maret 2025;644.2/1234-SP/TR 06 Maret 2025 400.7.22/1089 - KRK/45//Bid.Taru Tanggal 24 Februari 2025;503/0017-PKKPRNB/DPMPTSP/II/2025 Tanggal 12 Februari 2025 3101250002573 Tanggal 31 Januari 2025;2107230112343 Tanggal 21 Juli 2023 Tidak Diketahui Tidak Diketahui 3
22 41 / 1090 TIM AD HOC PERUMAHAN SUKAWANGI RESIDENCE No Telpon : 08112255770 Kp. Cihalimun RT 02/04 Ds. Cibeureum Kec. Kertasari Kab. Bandung PERUMAHAN SUKAWANGI RESIDENCE 1 648.11/ 1090 - SP / PR 25 Februari 2025 Fungsi Hunian Fungsi Hunian 2
23 42 / 1298 PT TIGA REKAN INDONESIA No Telpon : 08122444717 Jl Gradiul No 40 RT 04/07 Kel. Rancaekek Kencana Kec. Rancaekek Kab. Bandung PERUMAHAN GREEN HILL VILLAGE 16548 0.5917 9791.4516 648.11/1298 - SP/TR 17 Maret 2025 50.10.29.15/2742-REKTEK/Bid. Taru Tanggal 24 Juli 2024 2505240130006 Tanggal 25 Mei 2024;600.4.5/061/832-Ktr/Bid. TL/2025 Tgl. 19 Februari 2025 Fungsi Hunian Fungsi Hunian 2
24 43 / 1322 PT UNILOA ARDIYANTO INVESTAMA No Telpon : 081220180480 Jl Raya Ebah 103 Desa Sukamantri Kecamatan Paseh Kab. Bandung PERUMAHAN MARISON CIPAKU 19209 0.6146 11805.8514 648.11/1322 - SP/TR 18 Maret 2025 24042410313204051 Tanggal 24 JApril 2024 0238010110358 Tanggal 11 Januari 2024;500.10.29.7/Kep. 451-DLH/2025 Tgl. 13 Maret 2025 Fungsi Hunian Fungsi Hunian 2
25 44 / 1323 PT RADINAKA KRAMAT ABADI No Telpon : 082118781624 Jl. Sukamukti RT 01/06 Desa Sukamukti Kec. Katapang Kab. Bandung PERUMAHAN GAHARU PALEDANG RESIDENCE 14665 0.68003 9972.63995 648.11/1323 - SP/TR 18 Maret 2025 02032510213204087 Tanggal 02 Maret 2025 0238010110358 Tanggal 11 Januari 2024;600.4.5/064/1165-Ktr/Bid. TL/2025 Tgl. 12 Maret 2025 Fungsi Hunian Fungsi Hunian 2
26 45 / 1361 PT SANGKURIANG KRAMAT ABADI No Telpon : 082118781624 Kampung rancakasiat Desa Rancamulya Kec. Pameungpeuk Kab. Bandung PERUMAHAN PONDOK ASRI SUKAMUKTI 20451 0.6806 13918.9506 648.11/1361 - SP/TR 24 Maret 2025 500.10.29.15/3451-REKTEK/Bid.Taru Tanggal 26 September 2024 0811230037204 Tanggal 08 Nopember 2023;500.10.29.7/Kep.460-DLH/2025 Tgl. 21 Maret 2025 Fungsi Hunian Fungsi Hunian 2
27 46 / 1360 PT AUF ABDURACCHMAN JAYA No Telpon : 082118781624 Jl. Rancabungur rancakasiat Desa Malakasari Kec. Baleendah Kab. Bandung PERUMAHAN BUMI SHANGRILA RESIDENCE 12846 0.6412 8236.8552 648.11/1360 - SP/TR 24 Maret 2025 400.7.22/093/1390-KRK/Bid.Taru Tanggal 17 Maret 2025 0603250028082 Tanggal 06 Maret 2025;600.4.5/072/1270-Ktr/Bid.TL/2025 Tgl. 21 Maret 2025 Fungsi Hunian Fungsi Hunian 2
28 47 / 1142 ANTO DWI HARTANTO No Telpon : 082126215611 Jl. Elang V No 8 RT 08/01 Kel. Garuda Kec. Andir Kota Bandung PERGUDANGAN DAN PENYIMPANAN 1307 0.5616 734.0112 647/1142 - SP/TR 27 Februari 2025;648.11/823 - SP/TR 13 Februari 2025;644.2/1389 - SP/TR 26 Maret 2025;644.2/1388 - SP/TR 26 Maret 2025 500.10.29.15/3827-REKTEK/Bid.Taru Tanggal 17 Oktober 2024;500.10.29.15/3944-REKTEK/Bid.Taru Tanggal 28 Oktober 2024;503/0072-DPMPTSP/XI/2023 Tanggal 29 November 2023;400.7.22/1046-KRK/Bid.Taru Tanggal 21 Februari 2025 2009240075774 Tanggal 20 September 2024 2025;2009240075774 Tanggal 20 September 2025;500.10.29.7/Hep-461-DLH/2025 Tanggal 21 Maret 2025;0298000921888 Tanggal 24 Januari 2022 Usaha Besar (Non-Mikro) Fungsi Usaha 1
29 51 / 1161 PT INGRIA PRATAMA CAPITALINDO Tbk No Telpon : 087722361043 Ruko Pondok Cabe Mutiara Jl Pondok cabe No 27 Kel. Pamulang Kec. Pamulang Kota Tangerang Selatan REVISI 2 PERUMAHAN BUKIT ESMA CICALENGKA 2 74300 0.6292 46749.56 648.11/1161 - SP/TR 28 Februari 2025 50.10.29.15/2927-REKTEK/Bid. Taru Tanggal 14 Agustus 2024 591.4/005/IX-DPMPTSP/2019 Tanggal 09 September 2019;500.10.29.7/Kep.613-DLH/2024 Tgl. 18 November 2025 Fungsi Hunian Fungsi Hunian 2
30 52 / 1441 PT ABADI MUKTI KIRANA No Telpon : 087821848944 Jl Terusan jamika No 88 Kel. Jamika Kec. Bojongloa kaler Kota Bandung PERUMAHAN KOTA BARU ARJASARI 222816 1 222816 648.11/1441 - SP/TR 11 April 2025 400.7.28/1710/TR Tanggal 23 April 2024 9120108201236 Tanggal 13 Februari 2019;500.10.29.7/Kep.419-DLH/2025 Tgl. 03 Februari 2025 Fungsi Hunian Fungsi Hunian 2
31 53 / 1566 PT MAKMUR INDAH DAMAI No Telpon : 081394722234 Jl. Podomoro Boulevard utara I Desa Lengkong Kec. Bojongsoang Kab. Bandung PERUMAHAN BAROS INDAH RESIDENCE 17513 1 17513 647/1566 - SP/TR 25 April 2025 50.10.29.15/2507-REKTEK/Bid. Taru Tanggal 25 Juni 2024 2106240023693 Tanggal 21 Juni 2024;500.10.29.7/Kep.447-DLH/2024 Tgl. 10 Maret 2025 Fungsi Hunian Fungsi Hunian 2
32 54 / 1343 PT KARYA BUMI BESTARI No Telpon : 08156080428 Kembar Mas IV No 2A RT 05/09 Kel. Pasirluyu Kec. Regol Kota Bandung PERUMAHAN BESTARI MAS 26134 1 26134 648.11/1343 - SP/TR 20 Maret 2025;647/1565 - SP/TR 25 April 2025;648.1/1543 - SP/TR 17 April 2025 12042310213204004 Tanggal 12 April 2023;23122410113204057 Tanggal 23 Desember 2024;400.7.22/1047-KRK/42/Bid.Taru Tanggal 21 Februari 2025 1204230043635 Tanggal 12 April 2023;500.10.29.7/964/Bid. TL/2025 Tgl. 19 Februari 2025;9120304390956 Tanggal 05 Desember 2023;0307230050445 Tanggal 03 Juli 2023 Fungsi Hunian Fungsi Hunian 2
33 57 / 1372 TENNI DIANA No Telpon : 082116106640 Cikaahuripan RT 002/005 Kec. Neglasari Kota Tangerang PERADAGANGAN KHUSUS KARPET PERMADANI DAN PENUTUP DINDING DN LANTAI DI TOKO 1290 1 1290 644/1372 - SP/TR 26 Maret 2025;647/1557 - SP/TR 22 April 2025;640/1559 - SP/TR 22 April 2025;644/1371 - SP/TR 26 Maret 2025;644/1375 - SP/TR 26 Maret 2025;644/1373 - SP/TR 26 Maret 2025 500.10.29.15/4355-REKTEK/TR Tanggal 25 Agustus 2023;500.10.29.15/1073-REKTEK/TR Tanggal 04 Maret 2024;400.7.22/759-KRK/34/Bid.Taru Tanggal 11 Februari 2025;500.10.29.15/4654-REKTEK/Bid. Taru Tanggal 08 September 2023;500.10.29.15/4160-REKTEK/Bid. Taru Tanggal 15 Nopember 2024;500.10.29.15/2500-REKTEK/Bid. Taru Tanggal 19 Juni 2024 9120306652149 Tanggal 26 Juni 2019;0220107462528 Tanggal 08 September 2022;1283000240318 Tanggal 01 Februari 2021;600.4.5/071-KTR/Bid.TL/2025 Tgl. 05 Mei 2025;0220301251224 Tanggal 11 Agustus 2023;1263000210596 Tanggal 09 Februari 2021;1405240295325 5 Mei 2024 Tidak Diketahui Tidak Diketahui 1
34 63 / 1567 Ir. BERSIH TARIGANT No Telpon : 081322777581 Jl Multatuli No 3 rt 001/001 Ds/Kel. Lebakgede Kec. Coblong Kota Bandung PERUMAHAN TUSCANY HILL 23796 0.2428 5777.6688 648.11/1567 - SP/TR 25 April 2025 50.10.29.15/3829-REKTEK/Bid. Taru Tanggal 15 Oktober 2024 2007220014068 Tanggal 20 Juli 2025;500.10.29.7/Kep.429-DLH/2025 Tgl. 10 Maret 2025 Fungsi Hunian Fungsi Hunian 2
35 64 / 1682 PT CIPTA BERKAT PROPERTI No Telpon : 081910661980 Ruko Matahari Cigado No 25 Jalan Anggadireja Kel. Baleendah Kec. Baleendah Kab. Bandung PERUMAHAN GARDEN VIEW CICALENGKA 45666 1 45666 648.11/1682 - SP/TR 06 Mei 2025 50.10.29.15/3156-REKTEK/Bid. Taru Tanggal 05 September 2024 2310210017936 Tanggal 23 Oktober 2021;500.10.29.7/Kep.477-DLH/2025 Tgl. 17 April 2025 Fungsi Hunian Fungsi Hunian 2
36 64 / 1682 PT CIPTA BERKAT PROPERTI No Telpon : 081910661980 Ruko Matahari Cigado No 25 Jalan Anggadireja Kel. Baleendah Kec. Baleendah Kab. Bandung C. KWT PERUMAHAN 0 1 0 Fungsi Hunian Fungsi Hunian 1
37 65 / 1644 PT ARGUNA JAYA PROPERTY No Telpon : 081214211164 Jl Pidada IV/4 Denpasar BR/Link Sedana metra Kel. Ubung Kec. Denpasar Utara Kota Denpasar REVISI 1 PERUMAHAN ARGUNA SINDANGPANON 8553 0.53 4533.09 648.11/1644 - SP/TR 29 April 2025;644/1558 - SP/TR 22 April 2025 503/009/II-DPMPTSP/2020 Tanggal 25 Februari 2020;50.10.29.15/4063-REKTEK/Bid. Taru Tanggal 25 Nopember 2025 9120004890734 Tanggal 03 Agustus 2019;667/2081/TL Tgl. 08 Juni 2020;0609240042720001 Tanggal 06 September 2024 Fungsi Hunian Fungsi Hunian 1
38 67/ 1370 NENENG FATIMAH No Telpon : 08977980040 Jalan Batu Indah I No 26 RT 002/003 Kel. Batununggal Kec. Bandung Kidul Kota Bandung PERGUDANGAN DAN PENYIMPANAN 2034 1 2034 644/1370 - SP/TR 26 Maret 2025 50.10.29.15/3340-REKTEK/Bid. Taru Tanggal 18 September 2025 1009240038601 Tanggal 10 September 2024 Usaha Besar (Non-Mikro) Fungsi Usaha 1
39 68/ 1374 LILI JOJON No Telpon : 082219855556 Kp. Cibisoro RT 004/008 Desa Nanjung Kec. Mrgaasih Kab. Bandung PERGUDANGAN DAN PENYIMPANAN 1654 1 1654 644/1374 - SP/TR 26 Maret 2025;644.2/1683 - SP/TR 06 Mei 2025;645/1730 - SP/TR 07 Mei 2025 50.10.29.15/3210-REKTEK/Bid. Taru Tanggal 10 September 2024;400.7.22/1254-KRK/58/Bid. Taru Tanggal 10 Maret 2025;50.10.29.15/3443-REKTEK/Bid. Taru Tanggal 26 September 2024 1220000361065 Tanggal 16 Maret 2021;1712240056863 Tanggal 17 Desember 2024;0103230081544 Tanggal 01 Maret 2023;600.4.5/071/1503-Ktr/Bid. TL/2025 Tanggal 17 April 2025 Usaha Besar (Non-Mikro) Fungsi Usaha 1
40 71/ 1845 PT SANGKURIANG KRAMAT ABADI No Telpon : 082116602145 Kp. Rancakasiat Desa Rancamulya Kec. Pameungpeuk Kab. Bandung PERUMAHAN CLUSTER GAHARU EMERALD 19889 1 19889 648.11 /1845 - SP/TR 19 Mei 2025 400.7.22/1526-KRK/96/Bid. Taru Tanggal 22 April 2025 0811230037204 Tanggal 08 Nopember 2023;500.10.29.7/Kep. 489-DLH/2025 Tanggal 15 Mei 2025 Fungsi Hunian Fungsi Hunian 2
41 72/ 1731 PT MARGA TIRTA KENCANA No Telpon : 082130000146 Jlan BKR Lingkar selatan No 140 Kota Bandung PERUMAHAN TAMAN CIBADUYUT INDAH 2 DAN 3 205344 1 205344 648.11 /1731 - SP/TR 07 Mei 2025;648.11 /1946 - SP/TR 22 Mei 2025;643 /1881 - SP/TR 20 Mei 2025;644 /1684 - SP/TR 06 Mei 2025;648.12 /1825 - SP/TR 16 Mei 2025 591.4/002-BPMP/2010 Tanggal 10 Januari 2010;500.10.29.15/3108-REKTEK/Bid.taru Tanggal 29 Agustus 2024;500.10.29.15/3319-REKTEK/TR Tanggal 14 Juli 2023;12092410313204101 Tanggal 12 September 2024;400.7.22/1231-KRK/Bid.Taru Tanggal 06 Maret 2025 667/3803/DLH Tanggal 22 Desember 2016;9120204202309 Tanggal 20 Februari 2019;2002230028317 Tanggal 20 Februari 2023;600.4.5/073/1562-Ktr/Bid.TL/2025 Tanggal 23 April 2025;8120006931402 Tanggal 28 September 2022;12710006324580004 Tanggal 05 Maret 2025 Fungsi Hunian Fungsi Hunian 2
42 77/ 1879 PT PUTRA RAHMAN PRADANA No Telpon : 081312214962 Perum Cemerlang Permai Blok C No 16 Kel. Sukakarya Kec. Warudoyongf Kota Sukabumi REVISI 1 PERUMAHAN BUKIT PINUS BANIARAN 90711 1 90711 648.11 /1879 - SP/TR 20 Mei 2025 22122310313204009 Tanggal 22 Desember 2023 500.10.29.7/Kep.482-DLH/2025 Tanggal 24 April 2025 Fungsi Hunian Fungsi Hunian 2

56
Dockerfile Normal file
View File

@@ -0,0 +1,56 @@
FROM node:18 AS node-base
# Development stage
FROM node-base AS development
WORKDIR /var/www
COPY package*.json ./
RUN npm install
COPY . .
EXPOSE 5173
CMD ["npm", "run", "dev", "--", "--host", "0.0.0.0"]
# Production stage
FROM php:8.2-fpm AS production
WORKDIR /var/www
# Install PHP extensions
RUN apt-get update && apt-get install -y \
git curl zip unzip libpng-dev libonig-dev libxml2-dev libzip-dev \
&& docker-php-ext-install pdo_mysql mbstring exif pcntl bcmath gd zip
# Install Node.js
RUN curl -fsSL https://deb.nodesource.com/setup_18.x | bash - \
&& apt-get install -y nodejs
# Install Composer
COPY --from=composer:latest /usr/bin/composer /usr/bin/composer
# Copy application files
COPY . .
# Install dependencies
RUN composer install --no-dev --optimize-autoloader
# Install and build frontend assets
RUN npm install \
&& npm run build \
&& ls -la public/build \
&& mkdir -p public/assets \
&& cp -r public/build/* public/assets/ \
&& ls -la public/assets \
&& rm -rf node_modules \
&& rm -rf public/build
# Laravel caches
RUN php artisan config:clear \
&& php artisan route:clear \
&& php artisan view:clear \
&& php artisan optimize
RUN php artisan storage:link
# Permissions
RUN chown -R www-data:www-data /var/www && chmod -R 755 /var/www/storage /var/www/public
EXPOSE 9000
CMD ["php-fpm"]

136
README.md Executable file → Normal file
View File

@@ -1,66 +1,112 @@
<p align="center"><a href="https://laravel.com" target="_blank"><img src="https://raw.githubusercontent.com/laravel/art/master/logo-lockup/5%20SVG/2%20CMYK/1%20Full%20Color/laravel-logolockup-cmyk-red.svg" width="400" alt="Laravel Logo"></a></p>
# Usage icon
<p align="center">
<a href="https://github.com/laravel/framework/actions"><img src="https://github.com/laravel/framework/workflows/tests/badge.svg" alt="Build Status"></a>
<a href="https://packagist.org/packages/laravel/framework"><img src="https://img.shields.io/packagist/dt/laravel/framework" alt="Total Downloads"></a>
<a href="https://packagist.org/packages/laravel/framework"><img src="https://img.shields.io/packagist/v/laravel/framework" alt="Latest Stable Version"></a>
<a href="https://packagist.org/packages/laravel/framework"><img src="https://img.shields.io/packagist/l/laravel/framework" alt="License"></a>
</p>
search or pick icon in <a href="https://icon-sets.iconify.design/mingcute/?keyword=mingcute">here</a>
## About Laravel
# Set up queue for running automatically
Laravel is a web application framework with expressive, elegant syntax. We believe development must be an enjoyable and creative experience to be truly fulfilling. Laravel takes the pain out of development by easing common tasks used in many web projects, such as:
- Install Supervisor
- [Simple, fast routing engine](https://laravel.com/docs/routing).
- [Powerful dependency injection container](https://laravel.com/docs/container).
- Multiple back-ends for [session](https://laravel.com/docs/session) and [cache](https://laravel.com/docs/cache) storage.
- Expressive, intuitive [database ORM](https://laravel.com/docs/eloquent).
- Database agnostic [schema migrations](https://laravel.com/docs/migrations).
- [Robust background job processing](https://laravel.com/docs/queues).
- [Real-time event broadcasting](https://laravel.com/docs/broadcasting).
```
sudo apt update && sudo apt install supervisor -y
```
Laravel is accessible, powerful, and provides tools required for large, robust applications.
- Create Supervisor Config
## Learning Laravel
```
sudo nano /etc/supervisor/conf.d/laravel-worker.conf
Laravel has the most extensive and thorough [documentation](https://laravel.com/docs) and video tutorial library of all modern web application frameworks, making it a breeze to get started with the framework.
[program:laravel-worker]
process_name=%(program_name)s_%(process_num)02d
command=php /home/arifal/development/sibedas-pbg-web/artisan queue:work --queue=default --timeout=82800 --tries=1
autostart=true
autorestart=true
numprocs=1
redirect_stderr=true
stdout_logfile=/home/arifal/development/sibedas-pbg-web/storage/logs/worker.log
stopasgroup=true
killasgroup=true
```
You may also try the [Laravel Bootcamp](https://bootcamp.laravel.com), where you will be guided through building a modern Laravel application from scratch.
- Reload Supervisor
If you don't feel like reading, [Laracasts](https://laracasts.com) can help. Laracasts contains thousands of video tutorials on a range of topics including Laravel, modern PHP, unit testing, and JavaScript. Boost your skills by digging into our comprehensive video library.
```
sudo supervisorctl reread
sudo supervisorctl update
sudo supervisorctl start laravel-worker
sudo supervisorctl restart laravel-worker
sudo supervisorctl status
```
## Laravel Sponsors
# How to running
We would like to extend our thanks to the following sponsors for funding Laravel development. If you are interested in becoming a sponsor, please visit the [Laravel Partners program](https://partners.laravel.com).
- Install composer package
### Premium Partners
```
composer install
```
- **[Vehikl](https://vehikl.com/)**
- **[Tighten Co.](https://tighten.co)**
- **[WebReinvent](https://webreinvent.com/)**
- **[Kirschbaum Development Group](https://kirschbaumdevelopment.com)**
- **[64 Robots](https://64robots.com)**
- **[Curotec](https://www.curotec.com/services/technologies/laravel/)**
- **[Cyber-Duck](https://cyber-duck.co.uk)**
- **[DevSquad](https://devsquad.com/hire-laravel-developers)**
- **[Jump24](https://jump24.co.uk)**
- **[Redberry](https://redberry.international/laravel/)**
- **[Active Logic](https://activelogic.com)**
- **[byte5](https://byte5.de)**
- **[OP.GG](https://op.gg)**
- Install npm package
## Contributing
```
npm install && npm run build
```
Thank you for considering contributing to the Laravel framework! The contribution guide can be found in the [Laravel documentation](https://laravel.com/docs/contributions).
- Create symlinks storage
## Code of Conduct
```
php artisan storage:link
```
In order to ensure that the Laravel community is welcoming to all, please review and abide by the [Code of Conduct](https://laravel.com/docs/contributions#code-of-conduct).
- Running migration
## Security Vulnerabilities
```
php artisan migrate
```
If you discover a security vulnerability within Laravel, please send an e-mail to Taylor Otwell via [taylor@laravel.com](mailto:taylor@laravel.com). All security vulnerabilities will be promptly addressed.
- Running seeder
## License
```
php artisan db:seed
```
The Laravel framework is open-sourced software licensed under the [MIT license](https://opensource.org/licenses/MIT).
- 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

@@ -0,0 +1,288 @@
<?php
namespace App\Console\Commands;
use Illuminate\Console\Command;
use App\Models\SpatialPlanning;
use App\Models\RetributionProposal;
use App\Services\RetributionProposalService;
use Illuminate\Support\Facades\DB;
use Exception;
class CalculateRetributionProposalsCommand extends Command
{
/**
* The name and signature of the console command.
*
* @var string
*/
protected $signature = 'retribution:calculate-proposals
{--force : Force recalculate existing proposals}
{--limit= : Limit number of spatial plannings to process}
{--skip-existing : Skip spatial plannings that already have proposals}
{--dry-run : Show what would be processed without actually creating proposals}';
/**
* The console command description.
*
* @var string
*/
protected $description = 'Calculate retribution proposals for all spatial plannings';
protected RetributionProposalService $proposalService;
public function __construct(RetributionProposalService $proposalService)
{
parent::__construct();
$this->proposalService = $proposalService;
}
/**
* Execute the console command.
*/
public function handle()
{
$this->info('🧮 Starting Retribution Proposal Calculation...');
$this->newLine();
try {
// Get processing options
$force = $this->option('force');
$limit = $this->option('limit') ? (int) $this->option('limit') : null;
$skipExisting = $this->option('skip-existing');
$dryRun = $this->option('dry-run');
// Build query for spatial plannings
$query = SpatialPlanning::query();
if ($skipExisting && !$force) {
$query->whereDoesntHave('retributionProposals');
}
if ($limit) {
$query->limit($limit);
}
$spatialPlannings = $query->get();
$totalCount = $spatialPlannings->count();
if ($totalCount === 0) {
$this->warn('No spatial plannings found to process.');
return 0;
}
// Show processing summary
$this->info("📊 PROCESSING SUMMARY:");
$this->info(" Total Spatial Plannings: {$totalCount}");
$this->info(" Force Recalculate: " . ($force ? 'Yes' : 'No'));
$this->info(" Skip Existing: " . ($skipExisting ? 'Yes' : 'No'));
$this->info(" Dry Run: " . ($dryRun ? 'Yes' : 'No'));
$this->newLine();
if ($dryRun) {
$this->showDryRunPreview($spatialPlannings);
return 0;
}
// Confirm processing
if (!$this->confirm("Process {$totalCount} spatial plannings?")) {
$this->info('Operation cancelled.');
return 0;
}
// Process spatial plannings
$this->processRetributionCalculations($spatialPlannings, $force);
return 0;
} catch (Exception $e) {
$this->error('Error during retribution calculation: ' . $e->getMessage());
return 1;
}
}
/**
* Show dry run preview
*/
private function showDryRunPreview($spatialPlannings)
{
$this->info('🔍 DRY RUN PREVIEW:');
$this->newLine();
$processable = 0;
$withProposals = 0;
$withoutFunction = 0;
$withoutArea = 0;
foreach ($spatialPlannings as $spatial) {
$hasProposals = $spatial->retributionProposals()->exists();
$buildingFunction = $this->proposalService->detectBuildingFunction($spatial->getBuildingFunctionText());
$area = $spatial->getCalculationArea();
if ($hasProposals) {
$withProposals++;
}
if (!$buildingFunction) {
$withoutFunction++;
}
if ($area <= 0) {
$withoutArea++;
}
if ($buildingFunction && $area > 0) {
$processable++;
}
}
$this->table(
['Status', 'Count', 'Description'],
[
['✅ Processable', $processable, 'Can create retribution proposals'],
['🔄 With Existing Proposals', $withProposals, 'Already have proposals (will skip unless --force)'],
['❌ Missing Building Function', $withoutFunction, 'Cannot detect building function'],
['❌ Missing Area', $withoutArea, 'Area is zero or missing'],
]
);
$this->newLine();
$this->info("💡 To process: php artisan retribution:calculate-proposals");
$this->info("💡 To force recalculate: php artisan retribution:calculate-proposals --force");
}
/**
* Process retribution calculations
*/
private function processRetributionCalculations($spatialPlannings, $force)
{
$progressBar = $this->output->createProgressBar($spatialPlannings->count());
$progressBar->start();
$stats = [
'processed' => 0,
'skipped' => 0,
'errors' => 0,
'created_proposals' => 0
];
foreach ($spatialPlannings as $spatial) {
try {
$result = $this->processSingleSpatialPlanning($spatial, $force);
if ($result['status'] === 'processed') {
$stats['processed']++;
$stats['created_proposals'] += $result['proposals_created'];
} elseif ($result['status'] === 'skipped') {
$stats['skipped']++;
} else {
$stats['errors']++;
}
} catch (Exception $e) {
$stats['errors']++;
$this->newLine();
$this->error("Error processing spatial planning ID {$spatial->id}: " . $e->getMessage());
}
$progressBar->advance();
}
$progressBar->finish();
$this->newLine(2);
// Show final statistics
$this->showFinalStatistics($stats);
}
/**
* Process single spatial planning
*/
private function processSingleSpatialPlanning(SpatialPlanning $spatial, $force)
{
// Check if already has proposals
if (!$force && $spatial->retributionProposals()->exists()) {
return ['status' => 'skipped', 'reason' => 'already_has_proposals'];
}
// Detect building function
$buildingFunction = $this->proposalService->detectBuildingFunction($spatial->getBuildingFunctionText());
if (!$buildingFunction) {
return ['status' => 'error', 'reason' => 'no_building_function'];
}
// Get area
$totalArea = $spatial->getCalculationArea();
if ($totalArea <= 0) {
return ['status' => 'error', 'reason' => 'no_area'];
}
// Get number of floors
$numberOfFloors = max(1, $spatial->number_of_floors ?? 1);
// Delete existing proposals if force mode
if ($force) {
$spatial->retributionProposals()->delete();
}
$proposalsCreated = 0;
// Create proposals for each floor
for ($floor = 1; $floor <= $numberOfFloors; $floor++) {
// Calculate floor area (distribute total area across floors)
$floorArea = $totalArea / $numberOfFloors;
// Create retribution proposal
$proposal = $this->proposalService->createProposalForSpatialPlanning(
$spatial,
$buildingFunction->id,
$floor,
$floorArea,
$totalArea,
"Auto-generated from spatial planning calculation"
);
if ($proposal) {
$proposalsCreated++;
}
}
return [
'status' => 'processed',
'proposals_created' => $proposalsCreated
];
}
/**
* Show final statistics
*/
private function showFinalStatistics($stats)
{
$this->info('✅ CALCULATION COMPLETED!');
$this->newLine();
$this->table(
['Metric', 'Count'],
[
['Processed Successfully', $stats['processed']],
['Skipped (Already Exists)', $stats['skipped']],
['Errors', $stats['errors']],
['Total Proposals Created', $stats['created_proposals']],
]
);
if ($stats['errors'] > 0) {
$this->newLine();
$this->warn("⚠️ {$stats['errors']} spatial plannings had errors:");
$this->warn(" • Missing building function detection");
$this->warn(" • Missing or zero area");
$this->warn(" • Other calculation errors");
}
if ($stats['processed'] > 0) {
$this->newLine();
$this->info("🎉 Successfully created {$stats['created_proposals']} retribution proposals!");
$this->info("💡 You can view them using: php artisan retribution:list-proposals");
}
}
}

View File

@@ -2,6 +2,7 @@
namespace App\Console\Commands;
use App\Jobs\SyncronizeSIMBG;
use App\Services\ServiceSIMBG;
use Illuminate\Console\Command;
use \Illuminate\Support\Facades\Log;
@@ -28,13 +29,12 @@ class ExecuteScraping extends Command
private $service_simbg;
public function __construct(ServiceSIMBG $service_simbg){
$this->service_simbg = $service_simbg;
public function __construct(){
parent::__construct();
}
public function handle()
{
SyncronizeSIMBG::dispatch()->onQueue('default');
Log::info("running scheduler daily scraping");
$this->service_simbg->syncTaskList();
}
}

View File

@@ -0,0 +1,317 @@
<?php
namespace App\Console\Commands;
use App\Models\SpatialPlanning;
use Illuminate\Console\Command;
use Maatwebsite\Excel\Facades\Excel;
use Illuminate\Support\Facades\DB;
use Exception;
class InitSpatialPlanningDatas extends Command
{
/**
* The name and signature of the console command.
*
* @var string
*/
protected $signature = 'spatial:init {file? : Path to the CSV/Excel file} {--truncate : Clear existing data before import} {--safe-truncate : Clear only spatial plannings without retribution proposals} {--force-truncate : Force truncate by disabling foreign key checks}';
/**
* The console command description.
*
* @var string
*/
protected $description = 'Import spatial planning data from CSV/Excel file for retribution';
/**
* Execute the console command.
*/
public function handle()
{
$filePath = $this->argument('file') ?? 'public/templates/Data_2025___Estimasi_Jumlah_Lantai.csv';
$fullPath = storage_path('app/' . $filePath);
// Check if file exists
if (!file_exists($fullPath)) {
$this->error("File not found: {$fullPath}");
$this->info("Available files in templates:");
$this->listAvailableFiles();
return 1;
}
// Handle truncate options
if (($this->option('truncate') && $this->option('safe-truncate')) ||
($this->option('truncate') && $this->option('force-truncate')) ||
($this->option('safe-truncate') && $this->option('force-truncate'))) {
$this->error('Cannot use multiple truncate options together. Choose only one.');
return 1;
}
// Confirm truncate if requested
if ($this->option('truncate')) {
if ($this->confirm('This will delete all existing spatial planning data and related retribution proposals. Continue?')) {
$this->info('Truncating tables...');
try {
// First delete retribution proposals that reference spatial plannings
$deletedProposals = DB::table('retribution_proposals')
->whereNotNull('spatial_planning_id')
->count();
if ($deletedProposals > 0) {
DB::table('retribution_proposals')
->whereNotNull('spatial_planning_id')
->delete();
$this->info("Deleted {$deletedProposals} retribution proposals linked to spatial plannings.");
}
// Method 1: Try truncate with disabled foreign key checks
try {
DB::statement('SET FOREIGN_KEY_CHECKS = 0');
DB::table('spatial_plannings')->truncate();
DB::statement('SET FOREIGN_KEY_CHECKS = 1');
$this->info('Spatial plannings table truncated successfully.');
} catch (\Exception $truncateError) {
// Method 2: Fallback to delete if truncate fails
$this->warn('Truncate failed, using delete method...');
$deletedSpatial = DB::table('spatial_plannings')->delete();
$this->info("Deleted {$deletedSpatial} spatial planning records.");
// Reset auto increment
DB::statement('ALTER TABLE spatial_plannings AUTO_INCREMENT = 1');
}
} catch (\Exception $e) {
$this->error('Failed to truncate tables: ' . $e->getMessage());
return 1;
}
} else {
$this->info('Operation cancelled.');
return 0;
}
}
// Force truncate - disable foreign key checks and truncate everything
if ($this->option('force-truncate')) {
if ($this->confirm('This will FORCE truncate ALL spatial planning data by disabling foreign key checks. This is risky! Continue?')) {
$this->info('Force truncating with disabled foreign key checks...');
try {
DB::beginTransaction();
// Disable foreign key checks
DB::statement('SET FOREIGN_KEY_CHECKS = 0');
// Truncate both tables
DB::table('retribution_proposals')->truncate();
DB::table('spatial_plannings')->truncate();
// Re-enable foreign key checks
DB::statement('SET FOREIGN_KEY_CHECKS = 1');
$this->info('Force truncate completed successfully.');
DB::commit();
} catch (\Exception $e) {
DB::rollBack();
// Make sure to re-enable foreign key checks even on error
try {
DB::statement('SET FOREIGN_KEY_CHECKS = 1');
} catch (\Exception $fkError) {
$this->error('Failed to re-enable foreign key checks: ' . $fkError->getMessage());
}
$this->error('Failed to force truncate: ' . $e->getMessage());
return 1;
}
} else {
$this->info('Operation cancelled.');
return 0;
}
}
// Safe truncate - only delete spatial plannings without retribution proposals
if ($this->option('safe-truncate')) {
if ($this->confirm('This will delete only spatial planning data that have no retribution proposals. Continue?')) {
$this->info('Safe truncating spatial plannings...');
try {
DB::beginTransaction();
// Count spatial plannings with retribution proposals
$withProposals = DB::table('spatial_plannings')
->whereExists(function ($query) {
$query->select(DB::raw(1))
->from('retribution_proposals')
->whereColumn('retribution_proposals.spatial_planning_id', 'spatial_plannings.id');
})
->count();
// Delete spatial plannings without retribution proposals
$deletedCount = DB::table('spatial_plannings')
->whereNotExists(function ($query) {
$query->select(DB::raw(1))
->from('retribution_proposals')
->whereColumn('retribution_proposals.spatial_planning_id', 'spatial_plannings.id');
})
->delete();
$this->info("Deleted {$deletedCount} spatial plannings without retribution proposals.");
$this->info("Kept {$withProposals} spatial plannings that have retribution proposals.");
DB::commit();
} catch (\Exception $e) {
DB::rollBack();
$this->error('Failed to safe truncate: ' . $e->getMessage());
return 1;
}
} else {
$this->info('Operation cancelled.');
return 0;
}
}
$this->info("Starting import from: {$filePath}");
$this->info("Full path: {$fullPath}");
try {
DB::beginTransaction();
$data = Excel::toArray([], $fullPath);
if (empty($data) || empty($data[0])) {
$this->error('No data found in the file.');
return 1;
}
$rows = $data[0]; // Get first sheet
$headers = array_shift($rows); // Remove header row
$this->info("Found " . count($rows) . " data rows to import.");
$this->info("Headers: " . implode(', ', $headers));
$progressBar = $this->output->createProgressBar(count($rows));
$progressBar->start();
$imported = 0;
$skipped = 0;
foreach ($rows as $index => $row) {
try {
// Skip empty rows
if (empty(array_filter($row))) {
$skipped++;
$progressBar->advance();
continue;
}
// Map CSV columns to model attributes
$spatialData = [
'name' => $this->cleanString($row[1] ?? ''), // pemohon
'location' => $this->cleanString($row[2] ?? ''), // alamat
'activities' => $this->cleanString($row[3] ?? ''), // activities
'land_area' => $this->cleanNumber($row[4] ?? 0), // luas_lahan
'site_bcr' => $this->cleanNumber($row[5] ?? 0), // bcr_kawasan
'area' => $this->cleanNumber($row[6] ?? 0), // area
'no_tapak' => $this->cleanString($row[7] ?? ''), // no_tapak
'no_skkl' => $this->cleanString($row[8] ?? ''), // no_skkl
'no_ukl' => $this->cleanString($row[9] ?? ''), // no_ukl
'building_function' => $this->cleanString($row[10] ?? ''), // fungsi_bangunan
'sub_building_function' => $this->cleanString($row[11] ?? ''), // sub_fungsi_bangunan
'number_of_floors' => $this->cleanNumber($row[12] ?? 1), // jumlah_lantai
'number' => $this->cleanString($row[0] ?? ''), // no
'date' => now(), // Set current date
'kbli' => null, // Not in CSV, set as null
];
// Validate required fields
if (empty($spatialData['name']) && empty($spatialData['activities'])) {
$skipped++;
$progressBar->advance();
continue;
}
SpatialPlanning::create($spatialData);
$imported++;
} catch (Exception $e) {
$this->newLine();
$this->error("Error importing row " . ($index + 2) . ": " . $e->getMessage());
$skipped++;
}
$progressBar->advance();
}
$progressBar->finish();
$this->newLine(2);
DB::commit();
$this->info("Import completed successfully!");
$this->info("Imported: {$imported} records");
$this->info("Skipped: {$skipped} records");
return 0;
} catch (Exception $e) {
DB::rollBack();
$this->error("Import failed: " . $e->getMessage());
return 1;
}
}
/**
* Clean string data
*/
private function cleanString($value)
{
if (is_null($value)) return null;
return trim(str_replace(["\n", "\r", "\t"], ' ', $value));
}
/**
* Clean numeric data
*/
private function cleanNumber($value)
{
if (is_null($value) || $value === '') return 0;
// Remove non-numeric characters except decimal point
$cleaned = preg_replace('/[^0-9.]/', '', $value);
return is_numeric($cleaned) ? (float) $cleaned : 0;
}
/**
* List available template files
*/
private function listAvailableFiles()
{
$templatesPath = storage_path('app/public/templates');
if (is_dir($templatesPath)) {
$this->info("Files in storage/app/public/templates:");
$extensions = ['csv', 'xlsx', 'xls'];
foreach ($extensions as $ext) {
$files = glob($templatesPath . '/*.' . $ext);
foreach ($files as $file) {
$this->line(' - ' . basename($file));
}
}
}
$publicTemplatesPath = public_path('templates');
if (is_dir($publicTemplatesPath)) {
$this->info("Files in public/templates:");
$extensions = ['csv', 'xlsx', 'xls'];
foreach ($extensions as $ext) {
$files = glob($publicTemplatesPath . '/*.' . $ext);
foreach ($files as $file) {
$this->line(' - ' . basename($file));
}
}
}
}
}

View File

@@ -0,0 +1,321 @@
<?php
namespace App\Console\Commands;
use Illuminate\Console\Command;
use App\Models\SpatialPlanning;
use App\Models\RetributionProposal;
use App\Services\RetributionProposalService;
use Illuminate\Support\Facades\DB;
use Exception;
class ProcessSpatialPlanningRetributionCommand extends Command
{
/**
* The name and signature of the console command.
*
* @var string
*/
protected $signature = 'spatial:process-retribution
{--all : Process all spatial plannings}
{--new-only : Process only spatial plannings without retribution proposals}
{--force : Force recalculate existing retribution proposals}';
/**
* The console command description.
*
* @var string
*/
protected $description = 'Process and save retribution calculations for spatial plannings';
protected RetributionProposalService $proposalService;
public function __construct(RetributionProposalService $proposalService)
{
parent::__construct();
$this->proposalService = $proposalService;
}
/**
* Execute the console command.
*/
public function handle()
{
$this->info('🏗️ Processing Spatial Planning Retribution Calculations...');
$this->newLine();
try {
// Get options
$processAll = $this->option('all');
$newOnly = $this->option('new-only');
$force = $this->option('force');
// Build query
$query = SpatialPlanning::query();
if ($newOnly || (!$processAll && !$force)) {
$query->whereDoesntHave('retributionProposals');
$this->info('📋 Mode: Processing only spatial plannings WITHOUT retribution proposals');
} elseif ($processAll) {
$this->info('📋 Mode: Processing ALL spatial plannings');
}
$spatialPlannings = $query->get();
$totalCount = $spatialPlannings->count();
if ($totalCount === 0) {
$this->warn('❌ No spatial plannings found to process.');
$this->info('💡 Try running: php artisan spatial:init first');
return 0;
}
$this->info("📊 Found {$totalCount} spatial plannings to process");
$this->newLine();
// Show preview of what will be processed
$this->showProcessingPreview($spatialPlannings);
// Confirm processing
if (!$this->confirm("Process {$totalCount} spatial plannings and create retribution proposals?")) {
$this->info('Operation cancelled.');
return 0;
}
// Process all spatial plannings
$this->processAllSpatialPlannings($spatialPlannings, $force);
return 0;
} catch (Exception $e) {
$this->error('❌ Error during processing: ' . $e->getMessage());
return 1;
}
}
/**
* Show processing preview
*/
private function showProcessingPreview($spatialPlannings)
{
$this->info('🔍 PREVIEW:');
$canProcess = 0;
$cannotProcess = 0;
$hasExisting = 0;
$sampleData = [];
$errorReasons = [];
foreach ($spatialPlannings->take(5) as $spatial) {
$buildingFunction = $this->proposalService->detectBuildingFunction($spatial->getBuildingFunctionText());
$area = $spatial->getCalculationArea();
$floors = max(1, $spatial->number_of_floors ?? 1);
$hasProposals = $spatial->retributionProposals()->exists();
if ($hasProposals) {
$hasExisting++;
}
if ($buildingFunction && $area > 0) {
$canProcess++;
$sampleData[] = [
'ID' => $spatial->id,
'Name' => substr($spatial->name ?? 'N/A', 0, 30),
'Function' => $buildingFunction->name ?? 'N/A',
'Area' => number_format($area, 2),
'Floors' => $floors,
'Status' => $hasProposals ? '🔄 Has Proposals' : '✅ Ready'
];
} else {
$cannotProcess++;
if (!$buildingFunction) {
$errorReasons[] = 'Missing building function';
}
if ($area <= 0) {
$errorReasons[] = 'Missing/zero area';
}
}
}
// Show sample data table
if (!empty($sampleData)) {
$this->table(
['ID', 'Name', 'Function', 'Area (m²)', 'Floors', 'Status'],
$sampleData
);
}
// Show summary
$this->newLine();
$this->info("📈 SUMMARY:");
$this->info(" ✅ Can Process: {$canProcess}");
$this->info(" ❌ Cannot Process: {$cannotProcess}");
$this->info(" 🔄 Has Existing Proposals: {$hasExisting}");
if ($cannotProcess > 0) {
$this->warn(" ⚠️ Common Issues: " . implode(', ', array_unique($errorReasons)));
}
$this->newLine();
}
/**
* Process all spatial plannings
*/
private function processAllSpatialPlannings($spatialPlannings, $force)
{
$this->info('🚀 Starting processing...');
$this->newLine();
$progressBar = $this->output->createProgressBar($spatialPlannings->count());
$progressBar->start();
$stats = [
'processed' => 0,
'skipped' => 0,
'errors' => 0,
'total_proposals' => 0,
'total_amount' => 0
];
$errors = [];
foreach ($spatialPlannings as $spatial) {
try {
$result = $this->processSingleSpatialPlanning($spatial, $force);
if ($result['success']) {
$stats['processed']++;
$stats['total_proposals'] += $result['proposals_count'];
$stats['total_amount'] += $result['total_amount'];
} elseif ($result['skipped']) {
$stats['skipped']++;
} else {
$stats['errors']++;
$errors[] = "ID {$spatial->id}: " . $result['error'];
}
} catch (Exception $e) {
$stats['errors']++;
$errors[] = "ID {$spatial->id}: " . $e->getMessage();
}
$progressBar->advance();
}
$progressBar->finish();
$this->newLine(2);
// Show final results
$this->showFinalResults($stats, $errors);
}
/**
* Process single spatial planning
*/
private function processSingleSpatialPlanning(SpatialPlanning $spatial, $force)
{
// Check if already has proposals
if (!$force && $spatial->retributionProposals()->exists()) {
return ['success' => false, 'skipped' => true];
}
// Detect building function
$buildingFunction = $this->proposalService->detectBuildingFunction($spatial->getBuildingFunctionText());
if (!$buildingFunction) {
return ['success' => false, 'skipped' => false, 'error' => 'Cannot detect building function from: ' . $spatial->getBuildingFunctionText()];
}
// Get area
$totalArea = $spatial->getCalculationArea();
if ($totalArea <= 0) {
return ['success' => false, 'skipped' => false, 'error' => 'Area is zero or missing'];
}
// Get number of floors
$numberOfFloors = max(1, $spatial->number_of_floors ?? 1);
// Delete existing proposals if force mode
if ($force) {
$spatial->retributionProposals()->delete();
}
$proposalsCount = 0;
$totalAmount = 0;
// Create single proposal for the spatial planning (not per floor to prevent duplicates)
// Use the highest floor for IP ketinggian calculation (worst case scenario)
$highestFloor = $numberOfFloors;
$proposal = $this->proposalService->createProposalForSpatialPlanning(
$spatial,
$buildingFunction->id,
$highestFloor, // Use highest floor for calculation
$totalArea, // Use total area, not divided by floors
$totalArea,
"Auto-calculated from spatial planning data (floors: {$numberOfFloors})"
);
if ($proposal) {
$proposalsCount = 1;
$totalAmount = $proposal->total_retribution_amount;
}
return [
'success' => true,
'skipped' => false,
'proposals_count' => $proposalsCount,
'total_amount' => $totalAmount
];
}
/**
* Show final results
*/
private function showFinalResults($stats, $errors)
{
$this->info('🎉 PROCESSING COMPLETED!');
$this->newLine();
// Main statistics table
$this->table(
['Metric', 'Count'],
[
['✅ Successfully Processed', $stats['processed']],
['⏭️ Skipped (Already Has Proposals)', $stats['skipped']],
['❌ Errors', $stats['errors']],
['📄 Total Proposals Created', $stats['total_proposals']],
['💰 Total Retribution Amount', 'Rp ' . number_format($stats['total_amount'], 2)],
]
);
// Show success message
if ($stats['processed'] > 0) {
$this->newLine();
$this->info("🎊 SUCCESS!");
$this->info(" 📊 Created {$stats['total_proposals']} retribution proposals");
$this->info(" 💵 Total calculated amount: Rp " . number_format($stats['total_amount'], 2));
$this->info(" 📋 Processed {$stats['processed']} spatial plannings");
}
// Show errors if any
if ($stats['errors'] > 0) {
$this->newLine();
$this->warn("⚠️ ERRORS ENCOUNTERED:");
foreach (array_slice($errors, 0, 10) as $error) {
$this->warn("{$error}");
}
if (count($errors) > 10) {
$this->warn(" ... and " . (count($errors) - 10) . " more errors");
}
}
// Show next steps
$this->newLine();
$this->info("📋 NEXT STEPS:");
$this->info(" • View proposals: php artisan spatial:check-constraints");
$this->info(" • Check database: SELECT COUNT(*) FROM retribution_proposals;");
$this->info(" • Access via API: GET /api/retribution-proposals");
}
}

View File

@@ -0,0 +1,45 @@
<?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");
}
}

View File

@@ -0,0 +1,33 @@
<?php
namespace App\Console\Commands;
use App\Services\ServiceGoogleSheet;
use Illuminate\Console\Command;
class ScrapingLeaderData extends Command
{
/**
* The name and signature of the console command.
*
* @var string
*/
protected $signature = 'app:scraping-leader-data';
/**
* The console command description.
*
* @var string
*/
protected $description = 'Scraping leader data from google spreadsheet and save to database';
/**
* Execute the console command.
*/
public function handle()
{
$service_google_sheet = app(ServiceGoogleSheet::class);
$service_google_sheet->sync_leader_data();
$this->info('Leader data synced successfully');
}
}

View File

@@ -0,0 +1,125 @@
<?php
namespace App\Console\Commands;
use Illuminate\Console\Command;
use App\Services\DynamicRetributionCalculationService;
class TestExcelFormulaCommand extends Command
{
/**
* The name and signature of the console command.
*/
protected $signature = 'test:excel-formula';
/**
* The console command description.
*/
protected $description = 'Test Excel formula implementation for PBG retribution calculation';
/**
* Execute the console command.
*/
public function handle()
{
$service = new DynamicRetributionCalculationService();
$this->info('=== TESTING RUNDOWN 4 IMPLEMENTATION ===');
$this->info('Formula: =ROUNDDOWN(($E13*($F13+$G13+(0.5*I$3))),4)');
$this->newLine();
// Test 1: Hunian Sederhana
$this->info('1. HUNIAN SEDERHANA (1 Lantai, 100 m²)');
$result1 = $service->calculateRetribution(
buildingFunctionId: 10, // HUNIAN_SEDERHANA
floorLevel: 1,
luasBangunan: 100,
indeksLokasi: 'sedang',
includeInfrastructure: true
);
if ($result1['success']) {
$rundown4 = $result1['calculation_breakdown']['rundown_4_calculation'];
$retribution = $result1['calculation_breakdown']['retribution_calculation'];
$this->info(' ✓ Before ROUNDDOWN: ' . $rundown4['before_rounddown']);
$this->info(' ✓ After ROUNDDOWN(4): ' . $rundown4['after_rounddown']);
$this->info(' ✓ Basic Retribution: Rp ' . number_format($retribution['basic_amount']));
$this->info(' ✓ Infrastructure: Rp ' . number_format($retribution['infrastructure_amount']));
$this->info(' 💰 TOTAL: Rp ' . number_format($retribution['total_amount']));
} else {
$this->error(' ❌ Error: ' . $result1['error']);
}
$this->newLine();
// Test 2: Usaha Besar
$this->info('2. USAHA BESAR (3 Lantai, 200 m²)');
$result2 = $service->calculateRetribution(
buildingFunctionId: 9, // USAHA_BESAR
floorLevel: 3,
luasBangunan: 200,
indeksLokasi: 'tinggi',
includeInfrastructure: true
);
if ($result2['success']) {
$rundown4 = $result2['calculation_breakdown']['rundown_4_calculation'];
$retribution = $result2['calculation_breakdown']['retribution_calculation'];
$this->info(' ✓ Rundown 4 Result: ' . $rundown4['after_rounddown']);
$this->info(' ✓ Basic: Rp ' . number_format($retribution['basic_amount']));
$this->info(' ✓ Infrastructure: Rp ' . number_format($retribution['infrastructure_amount']));
$this->info(' 💰 TOTAL: Rp ' . number_format($retribution['total_amount']));
}
$this->newLine();
// Test 3: Keagamaan (Free)
$this->info('3. KEAGAMAAN (2 Lantai, 150 m²) - BEBAS RETRIBUSI');
$result3 = $service->calculateRetribution(
buildingFunctionId: 1, // KEAGAMAAN
floorLevel: 2,
luasBangunan: 150,
indeksLokasi: 'sedang',
includeInfrastructure: true
);
if ($result3['success']) {
$this->info(' ✓ Rundown 4 Result: ' . $result3['results']['h5_rundown4']);
$this->info(' 💸 RETRIBUSI BEBAS: Rp ' . number_format($result3['results']['total_retribution']));
}
$this->newLine();
// Test 4: Multi-Floor Calculation
$this->info('4. CAMPURAN BESAR - Multi Lantai (1-4 Lantai, 300 m²)');
$result4 = $service->calculateMultiFloorRetribution(
buildingFunctionId: 7, // CAMPURAN_BESAR
floors: [1, 2, 3, 4],
luasBangunan: 300,
indeksLokasi: 'tinggi'
);
if ($result4['success']) {
$this->info(' ✓ Per Floor Calculations:');
foreach ($result4['floor_details'] as $floor => $detail) {
$this->info(" Lantai {$floor}: H5={$detail['h5_rundown4']}, Total=Rp " . number_format($detail['total_retribution']));
}
$this->info(' 💰 TOTAL SEMUA LANTAI: Rp ' . number_format($result4['total_retribution']));
}
$this->newLine();
$this->info('=== RUNDOWN 4 VERIFICATION ===');
$this->info('✅ Formula: =ROUNDDOWN(($E13*($F13+$G13+(0.5*I$3))),4)');
$this->info('✅ ROUNDDOWN function with 4 decimal precision');
$this->info('✅ Tarif Dasar: Rp 7.035.000');
$this->info('✅ Infrastructure calculation: O3 * basic');
$this->info('✅ Code simplified - unused formulas removed');
$this->newLine();
$this->info('🎉 RUNDOWN 4 Implementation is CLEAN and VERIFIED!');
return Command::SUCCESS;
}
}

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,11 +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
{
@@ -18,12 +24,14 @@ class BigDataResumeController extends Controller
try{
$filterDate = $request->get("filterByDate");
// If filterByDate is "latest" or empty, get the most recent record
if (!$filterDate || $filterDate === "latest") {
$big_data_resume = BigdataResume::latest()->first();
$big_data_resume = BigdataResume::where('year', 'leader')->latest()->first();
if (!$big_data_resume) {
return $this->response_empty_resume();
}
} else {
// Filter by specific date
$big_data_resume = BigdataResume::whereDate('created_at', $filterDate)
$big_data_resume = BigdataResume::where('year', 'leader')
->whereDate('created_at', $filterDate)
->orderBy('id', 'desc')
->first();
@@ -37,15 +45,19 @@ class BigDataResumeController extends Controller
return response()->json(['message' => 'No data setting found']);
}
$target_pad = floatval(optional($data_settings->where('key', 'TARGET_PAD')->first())->value);
$tata_ruang = floatval(optional($data_settings->where('key', 'TATA_RUANG')->first())->value);
$realisasi_terbit_pbg_sum = floatval(optional($data_settings->where('key', 'REALISASI_TERBIT_PBG_SUM')->first())->value);
$realisasi_terbit_pbg_count = floatval(optional($data_settings->where('key', 'REALISASI_TERBIT_PBG_COUNT')->first())->value);
$menuggu_klik_dpmptsp_sum = floatval(optional($data_settings->where('key', 'MENUNGGU_KLIK_DPMPTSP_SUM')->first())->value);
$menuggu_klik_dpmptsp_count = floatval(optional($data_settings->where('key', 'MENUNGGU_KLIK_DPMPTSP_COUNT')->first())->value);
$proses_dinas_teknis_sum = floatval(optional($data_settings->where('key', 'PROSES_DINAS_TEKNIS_SUM')->first())->value);
$proses_dinas_teknis_count = floatval(optional($data_settings->where('key', 'PROSES_DINAS_TEKNIS_COUNT')->first())->value);
function cleanNumber($value) {
return floatval(str_replace('.', '', $value));
}
$target_pad = floatval(optional($data_settings->where('key', 'TARGET_PAD')->first())->value);
$realisasi_terbit_pbg_sum = cleanNumber(optional($data_settings->where('key', 'REALISASI_TERBIT_PBG_SUM')->first())->value);
$realisasi_terbit_pbg_count = cleanNumber(optional($data_settings->where('key', 'REALISASI_TERBIT_PBG_COUNT')->first())->value);
$menunggu_klik_dpmptsp_sum = cleanNumber(optional($data_settings->where('key', 'MENUNGGU_KLIK_DPMPTSP_SUM')->first())->value);
$menunggu_klik_dpmptsp_count = cleanNumber(optional($data_settings->where('key', 'MENUNGGU_KLIK_DPMPTSP_COUNT')->first())->value);
$proses_dinas_teknis_sum = cleanNumber(optional($data_settings->where('key', 'PROSES_DINAS_TEKNIS_SUM')->first())->value);
$proses_dinas_teknis_count = cleanNumber(optional($data_settings->where('key', 'PROSES_DINAS_TEKNIS_COUNT')->first())->value);
$tata_ruang = $big_data_resume->spatial_sum;
$kekurangan_potensi = $target_pad - $big_data_resume->potention_sum;
// percentage kekurangan potensi
@@ -81,8 +93,8 @@ class BigDataResumeController extends Controller
? round(($realisasi_terbit_pbg_sum / $big_data_resume->verified_sum) * 100, 2) : 0;
// percentage menunggu klik dpmptsp
$menunggu_klik_dpmptsp_percentage = $big_data_resume->verified_sum > 0 && $menuggu_klik_dpmptsp_sum > 0
? round(($menuggu_klik_dpmptsp_sum / $big_data_resume->verified_sum) * 100, 2) : 0;
$menunggu_klik_dpmptsp_percentage = $big_data_resume->verified_sum > 0 && $menunggu_klik_dpmptsp_sum > 0
? round(($menunggu_klik_dpmptsp_sum / $big_data_resume->verified_sum) * 100, 2) : 0;
// percentage proses_dinas_teknis
$proses_dinas_teknis_percentage = $big_data_resume->verified_sum > 0 && $proses_dinas_teknis_sum > 0
@@ -94,7 +106,8 @@ class BigDataResumeController extends Controller
'percentage' => 100,
],
'tata_ruang' => [
'sum' => $tata_ruang,
'sum' => $big_data_resume->spatial_sum,
'count' => $big_data_resume->spatial_count,
'percentage' => $tata_ruang_percentage,
],
'kekurangan_potensi' => [
@@ -132,8 +145,8 @@ class BigDataResumeController extends Controller
'percentage' => $realisasi_terbit_percentage
],
'menunggu_klik_dpmptsp' => [
'sum' => $menuggu_klik_dpmptsp_sum,
'count' => $menuggu_klik_dpmptsp_count,
'sum' => $menunggu_klik_dpmptsp_sum,
'count' => $menunggu_klik_dpmptsp_count,
'percentage' => $menunggu_klik_dpmptsp_percentage
],
'proses_dinas_teknis' => [
@@ -148,38 +161,166 @@ class BigDataResumeController extends Controller
}
}
/**
* Store a newly created resource in storage.
*/
public function store(Request $request)
{
//
public function bigdata_report(Request $request){
try{
$query = BigdataResume::query()->orderBy('id', 'desc');
if($request->filled('search')){
$query->where('year', 'LIKE', '%'.$request->input('search').'%');
}
$query = $query->paginate(config('app.paginate_per_page', 50));
return BigdataResumeResource::collection($query)->response()->getData(true);
}catch(\Exception $e){
Log::error($e->getMessage());
return response()->json(['message' => 'Error when fetching data'], 500);
}
}
/**
* Display the specified resource.
*/
public function show(string $id)
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);
}
}
/**
* Update the specified resource in storage.
*/
public function update(Request $request, string $id)
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');
}
/**
* Remove the specified resource from storage.
*/
public function destroy(string $id)
{
//
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

@@ -9,6 +9,7 @@ use App\Models\BusinessOrIndustry;
use Illuminate\Http\Request;
use Maatwebsite\Excel\Facades\Excel;
use \Illuminate\Support\Facades\Validator;
use App\Http\Requests\ExcelUploadRequest;
class BusinessOrIndustriesController extends Controller
{
/**
@@ -30,7 +31,7 @@ class BusinessOrIndustriesController extends Controller
});
}
return response()->json($query->paginate());
return response()->json($query->paginate(config('app.paginate_per_page', 50)));
}
/**
@@ -79,29 +80,15 @@ class BusinessOrIndustriesController extends Controller
}
}
public function upload(Request $request){
if ($request->hasFile('file')) {
$file = $request->file('file');
}
// Validasi file
$validator = Validator::make($request->all(), [
'file' => 'required|mimes:xlsx,xls|max:102400', // Max 100MB
]);
if ($validator->fails()) {
return response()->json([
'message' => 'File validation failed.',
'errors' => $validator->errors()
], 400);
}
public function upload(ExcelUploadRequest $request){
try {
// Ambil file dari request
$file = $request->file('file');
if(!$request->hasFile('file')){
return response()->json([
'error' => 'No file provided'
], 400);
}
// Menggunakan Laravel Excel untuk mengimpor file
$file = $request->file('file');
Excel::import(new BusinessIndustriesImport, $file);
// Jika sukses, kembalikan respons sukses

View File

@@ -0,0 +1,117 @@
<?php
namespace App\Http\Controllers\Api;
use Illuminate\Http\Request;
use App\Services\OpenAIService;
use App\Http\Controllers\Controller;
use Illuminate\Http\Response;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Log;
class ChatbotController extends Controller
{
protected $openAIService;
public function __construct(OpenAIService $openAIService)
{
$this->openAIService = $openAIService;
}
public function generateText(Request $request)
{
$request->validate([
'tab_active' => 'required|string',
'prompt' => 'required|string',
]);
$tab_active = $request->input('tab_active');
$main_content = match ($tab_active) {
"count-retribusi" => "RETRIBUTION",
"document-validation" => "DOCUMENT VALIDATION",
"data-information" => "DATA SUMMARY",
default => "UNKNOWN",
};
$chatHistory = $request->input('chatHistory');
Log::info('Chat history sebelum disimpan:', ['history' => $chatHistory]);
if ($main_content === "UNKNOWN") {
return response()->json(['response' => 'Invalid tab_active value.'], 400);
}
// info($main_content);
$queryResponse = $this->openAIService->generateQueryBasedMainContent($request->input('prompt'), $main_content, $chatHistory);
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);
$nlpResult = $this->openAIService->generateNLPFromQuery($request->input('prompt'), $formattedResultQuery);
$finalGeneratedText =$this->openAIService->generateFinalText($nlpResult);
return response()->json(['response' => $finalGeneratedText, 'nlpResponse' => $queryResponse]);
}
public function mainGenerateText(Request $request)
{
// Log hanya data yang relevan
info("Received prompt: " . $request->input('prompt'));
// Validasi input
$request->validate([
'prompt' => 'required|string',
]);
try {
// Panggil service untuk generate text
$classifyResponse = $this->openAIService->classifyMainGenerateText($request->input('prompt'));
info($classifyResponse);
// Pastikan hasil klasifikasi valid sebelum melanjutkan
$validCategories = [
'reklame', 'business_or_industries', 'customers',
'pbg', 'retribusi', 'spatial_plannings',
'tourisms', 'umkms'
];
if (!in_array($classifyResponse, $validCategories)) {
return response()->json([
'error' => ''
], 400);
}
$chatHistory = $request->input('chatHistory');
Log::info('Chat history sebelum disimpan:', ['history' => $chatHistory]);
$queryResponse = $this->openAIService->createMainQuery($classifyResponse, $request->input('prompt'), $chatHistory);
info($queryResponse);
$formattedResultQuery = "[]";
$queryResponse = str_replace(['```sql', '```'], '', $queryResponse);
$queryResult = DB::select($queryResponse);
$formattedResultQuery = json_encode($queryResult, JSON_PRETTY_PRINT);
$nlpResult = $this->openAIService->generateNLPFromQuery($request->input('prompt'), $formattedResultQuery);
$finalGeneratedText =$this->openAIService->generateFinalText($nlpResult);
return response()->json(['response' => $finalGeneratedText, 'nlpResponse' => $queryResponse]);
} catch (\Exception $e) {
// Tangani error dan log exception
\Log::error("Error generating text: " . $e->getMessage());
return response()->json([
'error' => ''
], 500);
}
}
}

View File

@@ -22,9 +22,9 @@ class CustomersController extends Controller
if ($request->has('search') &&!empty($request->get('search'))) {
$query = $query->where('nomor_pelanggan', 'LIKE', '%'.$request->get('search').'%')
->orWhere('nama', 'LIKE', '%'.$request->get('search').'%')
->orWhere('kota_palayanan', 'LIKE', '%'.$request->get('search').'%');
->orWhere('kota_pelayanan', 'LIKE', '%'.$request->get('search').'%');
}
return CustomersResource::collection($query->paginate());
return CustomersResource::collection($query->paginate(config('app.paginate_per_page', 50)));
}
/**

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,91 @@
<?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 = 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
");
$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

@@ -24,7 +24,7 @@ class ImportDatasourceController extends Controller
$search = $request->get("search");
$query->where('status', 'like', "%".$search."%");
}
return ImportDatasourceResource::collection($query->paginate());
return ImportDatasourceResource::collection($query->paginate(config('app.paginate_per_page', 50)));
}
public function checkImportDatasource(){

View File

@@ -7,6 +7,7 @@ use App\Models\Advertisement;
use App\Models\Customer;
use App\Models\SpatialPlanning;
use Illuminate\Http\Request;
use App\Models\TourismBasedKBLI;
class LackOfPotentialController extends Controller
{
@@ -16,11 +17,17 @@ class LackOfPotentialController extends Controller
$total_reklame = Advertisement::count();
$total_pdam = Customer::count();
$total_tata_ruang = SpatialPlanning::count();
$total_tata_ruang_usaha = SpatialPlanning::where('building_function','like', '%usaha%')->count();
$total_tata_ruang_non_usaha = SpatialPlanning::where('building_function','like', '%hunian%')->count();
$data_report_tourism = TourismBasedKBLI::all();
return response()->json([
'total_reklame' => $total_reklame,
'total_pdam' => $total_pdam,
'total_tata_ruang' => $total_tata_ruang
'total_tata_ruang' => $total_tata_ruang,
'total_tata_ruang_usaha' => $total_tata_ruang_usaha,
'total_tata_ruang_non_usaha' => $total_tata_ruang_non_usaha,
'data_report' => $data_report_tourism,
], 200);
}catch(\Exception $e){
return response()->json([

View File

@@ -22,7 +22,8 @@ class MenusController extends Controller
$query = $query->where("name", "like", "%".$request->get("search")."%");
}
return response()->json($query->paginate());
// 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,14 +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').'%');
$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

@@ -20,7 +20,7 @@ class RolesController extends Controller
$query = $query->where('name', 'like', '%'. $request->get('search') . '%');
}
return response()->json($query->paginate());
return response()->json($query->paginate(config('app.paginate_per_page', 50)));
}
/**

View File

@@ -4,8 +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;
@@ -22,40 +30,33 @@ class ScrapingController extends Controller
return $this->resError("Failed to execute while processing another scraping");
}
// run service artisan command
Artisan::call("app:execute-scraping");
return $this->resSuccess("Success execute scraping service please wait");
// 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

@@ -39,7 +39,7 @@ class TourismController extends Controller
$tourisms->village_name = $village ? $village->village_name : null;
$district = DB::table('districts')->where('district_code', $tourisms->district_code)->first();
$tourisms->district_name = $village ? $village->village_name : null;
$tourisms->district_name = $district ? $district->district_name : null;
return $tourisms;
});

View File

@@ -11,6 +11,7 @@ use App\Traits\GlobalApiResponse;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Hash;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Log;
class UsersController extends Controller
{
@@ -29,9 +30,10 @@ 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());
return UserResource::collection($query->paginate(config('app.paginate_per_page', 50)));
}
public function logout(Request $request){
$request->user()->tokens()->delete();
@@ -83,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

@@ -36,15 +36,68 @@ class AuthenticatedSessionController extends Controller
// Ambil user yang sedang login
$user = Auth::user();
// Buat token untuk API
$token = $user->createToken(env('APP_KEY'))->plainTextToken;
// Hapus token lama jika ada
$user->tokens()->delete();
// Simpan token di session (bisa digunakan di JavaScript)
// Buat token untuk API dengan scope dan expiration
$tokenName = config('app.name', 'Laravel') . '-' . $user->id . '-' . time();
// Token dengan scope (opsional)
$token = $user->createToken($tokenName, ['*'], now()->addDays(30))->plainTextToken;
// Simpan token di session untuk digunakan di frontend
session(['api_token' => $token]);
return redirect()->intended(RouteServiceProvider::HOME);
}
/**
* Generate API token for authenticated user
*
* @param \Illuminate\Http\Request $request
* @return \Illuminate\Http\JsonResponse
*/
public function generateApiToken(Request $request)
{
$user = Auth::user();
if (!$user) {
return response()->json(['error' => 'Unauthorized'], 401);
}
// Delete existing tokens
$user->tokens()->delete();
// Generate new token
$tokenName = config('app.name', 'Laravel') . '-' . $user->id . '-' . time();
$token = $user->createToken($tokenName, ['*'], now()->addDays(30))->plainTextToken;
return response()->json([
'token' => $token,
'token_type' => 'Bearer',
'expires_in' => 30 * 24 * 60 * 60, // 30 days in seconds
]);
}
/**
* Revoke API token for authenticated user
*
* @param \Illuminate\Http\Request $request
* @return \Illuminate\Http\JsonResponse
*/
public function revokeApiToken(Request $request)
{
$user = Auth::user();
if (!$user) {
return response()->json(['error' => 'Unauthorized'], 401);
}
$user->tokens()->delete();
return response()->json(['message' => 'All tokens revoked successfully']);
}
/**
* Destroy an authenticated session.
*

View File

View File

View File

0
app/Http/Controllers/Auth/NewPasswordController.php Executable file → Normal file
View File

View File

0
app/Http/Controllers/Auth/RegisteredUserController.php Executable file → Normal file
View File

0
app/Http/Controllers/Auth/VerifyEmailController.php Executable file → Normal file
View File

View File

@@ -0,0 +1,48 @@
<?php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
class BigdataResumesController extends Controller
{
/**
* Display a listing of the resource.
*/
public function index()
{
return view('bigdata-resumes.index');
}
/**
* Show the form for creating a new resource.
*/
public function create()
{
//
}
/**
* Display the specified resource.
*/
public function show(string $id)
{
//
}
/**
* Show the form for editing the specified resource.
*/
public function edit(string $id)
{
//
}
/**
* Remove the specified resource from storage.
*/
public function destroy(string $id)
{
//
}
}

View File

@@ -4,63 +4,40 @@ namespace App\Http\Controllers;
use App\Models\BusinessOrIndustry;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Auth;
class BusinessOrIndustriesController extends Controller
{
/**
* Display a listing of the resource.
*/
public function index()
public function index(Request $request)
{
return view('business-industries.index');
$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

@@ -0,0 +1,17 @@
<?php
namespace App\Http\Controllers\Chatbot;
use App\Http\Controllers\Controller;
use Illuminate\Http\Request;
class ChatbotController extends Controller
{
/**
* Displya a listing of the resource
*/
public function index()
{
return view('chatbot.index');
}
}

View File

@@ -0,0 +1,17 @@
<?php
namespace App\Http\Controllers\ChatbotPimpinan;
use App\Http\Controllers\Controller;
use Illuminate\Http\Request;
class ChatbotPimpinanController extends Controller
{
/**
* Display a listing of the resource
*/
public function index()
{
return view('chatbot-pimpinan.index');
}
}

49
app/Http/Controllers/Controller.php Executable file → Normal file
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

@@ -4,23 +4,34 @@ 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()
public function index(Request $request)
{
return view('customers.index');
$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('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,11 +13,21 @@ 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()
{
return view('dashboards.pbg');
}
public function leader()
{
$latest_import_datasource = ImportDatasource::latest()->first();
$latest_created = $latest_import_datasource ?
$latest_import_datasource->created_at->format("j F Y H:i:s") : null;
$menus = Menu::all();
return view('dashboards.leader', compact('latest_created', 'menus'));
}
}

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

@@ -6,15 +6,23 @@ use App\Http\Controllers\Controller;
use App\Models\Advertisement;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Auth;
class AdvertisementController extends Controller
{
/**
* Display a listing of the resource.
*/
public function index()
public function index(Request $request)
{
return view('data.advertisements.index');
$menuId = $request->query('menu_id', 0);
$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.advertisements.index', compact('creator', 'updater', 'destroyer','menuId'));
}
/**
@@ -29,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';
@@ -47,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';
@@ -62,7 +72,7 @@ class AdvertisementController extends Controller
// Pastikan model ditemukan
if (!$modelInstance) {
info("AdvertisementController@edit: Model tidak ditemukan.");
return redirect()->route('advertisements.index')->with('error', 'Advertisement not found');
return redirect()->route('web.advertisements.index')->with('error', 'Advertisement not found');
}
// Mengambil dan memetakan village_name dan district_name
@@ -86,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

@@ -11,24 +11,33 @@ class SpatialPlanningController extends Controller
/**
* Display a listing of the resource.
*/
public function index()
public function index(Request $request)
{
return view('data.spatialPlannings.index');
$menuId = $request->query('menu_id', 0);
$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.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";
@@ -39,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';
@@ -78,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

@@ -6,30 +6,39 @@ use App\Http\Controllers\Controller;
use App\Models\Tourism;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Auth;
class TourismController extends Controller
{
/**
* Display a listing of the resource
*/
public function index()
public function index(Request $request)
{
return view('data.tourisms.index');
$menuId = $request->query('menu_id', 0);
$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.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';
@@ -44,21 +53,22 @@ 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';
$modelInstance = Tourism::find($id);
// Pastikan model ditemukan
if (!$modelInstance) {
return redirect()->route('tourisms.index') ->with('error', 'Pariwisata tidak ditemukan');
return redirect()->route('web-tourisms.index') ->with('error', 'Pariwisata tidak ditemukan');
}
// Mengambil dan memetakan village_name dan district_name
@@ -78,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

@@ -6,30 +6,39 @@ use App\Http\Controllers\Controller;
use App\Models\Umkm;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Auth;
class UmkmController extends Controller
{
/**
* Display a listing of the resource.
*/
public function index()
public function index(Request $request)
{
return view('data.umkm.index');
$menuId = $request->query('menu_id', 0);
$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.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';
@@ -47,20 +56,21 @@ 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);
// Pastikan model ditemukan
if (!$modelInstance) {
return redirect()->route('umkm.index')->with('error', 'Umkm not found');
return redirect()->route('web-umkm.index')->with('error', 'Umkm not found');
}
// Mengambil dan memetakan village_name dan district_name
@@ -96,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

@@ -8,23 +8,31 @@ use Exception;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Log;
use Illuminate\Support\Facades\Request;
use Illuminate\Support\Facades\Auth;
use Illuminate\Http\Request as IndexRequest;
class DataSettingController extends Controller
{
/**
* Display a listing of the resource.
*/
public function index()
public function index(IndexRequest $request)
{
return view("data-settings.index");
$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'));
}
/**
@@ -57,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

@@ -13,6 +13,7 @@ use Illuminate\Support\Facades\Hash;
use App\Models\User;
use App\Traits\GlobalApiResponse;
use Illuminate\Auth\Events\Registered;
use Illuminate\Support\Facades\Auth;
class UsersController extends Controller
{
@@ -21,13 +22,20 @@ class UsersController extends Controller
$users = User::all();
return $this->resSuccess($users);
}
public function index(){
public function index(Request $request){
$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'));
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([
@@ -65,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

@@ -12,18 +12,35 @@ class MenusController extends Controller
/**
* Display a listing of the resource.
*/
public function index()
public function index(Request $request)
{
return view('menus.index');
$menuId = (int) $request->query('menu_id', 0);
$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('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'));
}
/**
@@ -56,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'));
}
/**
@@ -110,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,18 +2,37 @@
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
{
/**
* Display a listing of the resource.
*/
public function index()
public function index(Request $request)
{
return view('pbg_task.index');
$menuId = $request->query('menu_id') ?? $request->input('menu_id');
$filter = $request->query('filter');
$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(),
]);
}
/**
@@ -38,7 +57,9 @@ 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'])->findOrFail($id);
return view("pbg_task.show", compact("data"));
$statusOptions = PbgTaskStatus::getStatuses();
$applicationTypes = PbgTaskApplicationTypes::labels();
return view("pbg_task.show", compact("data", 'statusOptions', 'applicationTypes'));
}
/**

View File

@@ -0,0 +1,295 @@
<?php
namespace App\Http\Controllers;
use App\Models\RetributionProposal;
use App\Models\SpatialPlanning;
use App\Models\BuildingFunction;
use App\Services\RetributionProposalService;
use Illuminate\Http\Request;
use Illuminate\Http\JsonResponse;
class RetributionProposalController extends Controller
{
protected RetributionProposalService $proposalService;
public function __construct(RetributionProposalService $proposalService)
{
$this->proposalService = $proposalService;
}
/**
* Display a listing of retribution proposals
*/
public function index(Request $request): JsonResponse
{
$query = RetributionProposal::with(['spatialPlanning', 'buildingFunction', 'retributionFormula']);
// Filtering
if ($request->has('building_function_id')) {
$query->where('building_function_id', $request->building_function_id);
}
if ($request->has('spatial_planning_id')) {
$query->where('spatial_planning_id', $request->spatial_planning_id);
}
if ($request->has('floor_number')) {
$query->where('floor_number', $request->floor_number);
}
if ($request->has('has_spatial_planning')) {
if ($request->boolean('has_spatial_planning')) {
$query->whereNotNull('spatial_planning_id');
} else {
$query->whereNull('spatial_planning_id');
}
}
// Search
if ($request->has('search')) {
$search = $request->search;
$query->where(function ($q) use ($search) {
$q->where('proposal_number', 'like', "%{$search}%")
->orWhere('notes', 'like', "%{$search}%")
->orWhereHas('spatialPlanning', function ($sq) use ($search) {
$sq->where('name', 'like', "%{$search}%");
})
->orWhereHas('buildingFunction', function ($bq) use ($search) {
$bq->where('name', 'like', "%{$search}%");
});
});
}
// Sorting
$sortBy = $request->get('sort_by', 'created_at');
$sortOrder = $request->get('sort_order', 'desc');
$query->orderBy($sortBy, $sortOrder);
// Pagination
$perPage = $request->get('per_page', 15);
$proposals = $query->paginate($perPage);
return response()->json([
'success' => true,
'data' => $proposals,
'meta' => [
'total_amount' => RetributionProposal::sum('total_retribution_amount'),
'total_proposals' => RetributionProposal::count(),
'formatted_total_amount' => 'Rp ' . number_format(RetributionProposal::sum('total_retribution_amount'), 0, ',', '.')
]
]);
}
/**
* Store a new retribution proposal
*/
public function store(Request $request): JsonResponse
{
$request->validate([
'spatial_planning_id' => 'nullable|exists:spatial_plannings,id',
'building_function_id' => 'required|exists:building_functions,id',
'floor_number' => 'required|integer|min:1|max:10',
'floor_area' => 'required|numeric|min:0.01',
'total_building_area' => 'nullable|numeric|min:0.01',
'notes' => 'nullable|string|max:1000'
]);
try {
if ($request->spatial_planning_id) {
$spatialPlanning = SpatialPlanning::findOrFail($request->spatial_planning_id);
$proposal = $this->proposalService->createProposalForSpatialPlanning(
$spatialPlanning,
$request->building_function_id,
$request->floor_number,
$request->floor_area,
$request->total_building_area,
$request->notes
);
} else {
$proposal = $this->proposalService->createStandaloneProposal(
$request->building_function_id,
$request->floor_number,
$request->floor_area,
$request->total_building_area,
$request->notes
);
}
$proposal->load(['spatialPlanning', 'buildingFunction', 'retributionFormula']);
return response()->json([
'success' => true,
'message' => 'Retribution proposal created successfully',
'data' => $proposal
], 201);
} catch (\Exception $e) {
return response()->json([
'success' => false,
'message' => 'Failed to create retribution proposal',
'error' => $e->getMessage()
], 400);
}
}
/**
* Display the specified retribution proposal
*/
public function show(int $id): JsonResponse
{
$proposal = RetributionProposal::with(['spatialPlanning', 'buildingFunction', 'retributionFormula'])
->findOrFail($id);
return response()->json([
'success' => true,
'data' => $proposal
]);
}
/**
* Update the specified retribution proposal
*/
public function update(Request $request, int $id): JsonResponse
{
$proposal = RetributionProposal::findOrFail($id);
$request->validate([
'notes' => 'nullable|string|max:1000'
]);
$proposal->update($request->only(['notes']));
$proposal->load(['spatialPlanning', 'buildingFunction', 'retributionFormula']);
return response()->json([
'success' => true,
'message' => 'Retribution proposal updated successfully',
'data' => $proposal
]);
}
/**
* Remove the specified retribution proposal
*/
public function destroy(int $id): JsonResponse
{
$proposal = RetributionProposal::findOrFail($id);
$proposal->delete();
return response()->json([
'success' => true,
'message' => 'Retribution proposal deleted successfully'
]);
}
/**
* Get retribution proposal statistics
*/
public function statistics(): JsonResponse
{
$stats = $this->proposalService->getStatistics();
return response()->json([
'success' => true,
'data' => $stats
]);
}
/**
* Get total sum of all retribution proposals
*/
public function totalSum(): JsonResponse
{
$totalAmount = RetributionProposal::sum('total_retribution_amount');
return response()->json([
'success' => true,
'data' => [
'total_amount' => $totalAmount,
'formatted_total_amount' => 'Rp ' . number_format($totalAmount, 0, ',', '.'),
'total_proposals' => RetributionProposal::count()
]
]);
}
/**
* Get building functions list
*/
public function buildingFunctions(): JsonResponse
{
$buildingFunctions = BuildingFunction::whereNotNull('parent_id')
->with(['parameter'])
->orderBy('name')
->get();
return response()->json([
'success' => true,
'data' => $buildingFunctions
]);
}
/**
* Auto-detect building function and create proposal
*/
public function autoCreateProposal(Request $request): JsonResponse
{
$request->validate([
'spatial_planning_id' => 'nullable|exists:spatial_plannings,id',
'building_function_text' => 'required|string',
'floor_number' => 'required|integer|min:1|max:10',
'floor_area' => 'required|numeric|min:0.01',
'total_building_area' => 'nullable|numeric|min:0.01',
'notes' => 'nullable|string|max:1000'
]);
try {
// Auto-detect building function
$buildingFunction = $this->proposalService->detectBuildingFunction($request->building_function_text);
if (!$buildingFunction) {
return response()->json([
'success' => false,
'message' => 'Could not detect building function from text',
'suggestion' => 'Please specify building function manually'
], 400);
}
if ($request->spatial_planning_id) {
$spatialPlanning = SpatialPlanning::findOrFail($request->spatial_planning_id);
$proposal = $this->proposalService->createProposalForSpatialPlanning(
$spatialPlanning,
$buildingFunction->id,
$request->floor_number,
$request->floor_area,
$request->total_building_area,
$request->notes
);
} else {
$proposal = $this->proposalService->createStandaloneProposal(
$buildingFunction->id,
$request->floor_number,
$request->floor_area,
$request->total_building_area,
$request->notes
);
}
$proposal->load(['spatialPlanning', 'buildingFunction', 'retributionFormula']);
return response()->json([
'success' => true,
'message' => 'Retribution proposal created successfully with auto-detected building function',
'data' => $proposal,
'detected_building_function' => $buildingFunction->name
], 201);
} catch (\Exception $e) {
return response()->json([
'success' => false,
'message' => 'Failed to create retribution proposal',
'error' => $e->getMessage()
], 400);
}
}
}

View File

@@ -10,23 +10,31 @@ use Illuminate\Http\Request;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Log;
use Illuminate\Support\Facades\Schema;
use Illuminate\Support\Facades\Auth;
class RolesController extends Controller
{
/**
* Display a listing of the resource.
*/
public function index()
public function index(Request $request)
{
return view("roles.index");
$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("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'));
}
/**
@@ -59,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'));
}
/**
@@ -100,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());
}
@@ -113,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",
@@ -123,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] = [
@@ -137,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());

0
app/Http/Controllers/RoutingController.php Executable file → Normal file
View File

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;
@@ -13,16 +15,36 @@ class SyncronizeController extends Controller
$this->service_simbg = $service_simbg;
}
public function index(Request $request){
return view('settings.syncronize.index');
$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('settings.syncronize.index', compact('creator', 'updater', 'destroyer'));
}
public function syncPbgTask(){
$res = $this->service_simbg->syncTaskList();
$res = $this->service_simbg->syncTaskPBG();
return $res;
}
public function syncronizeTask(Request $request){
$res = $this->service_simbg->syncTaskList();
$res = $this->service_simbg->syncTaskPBG();
return redirect()->back()->with('success', 'Processing completed successfully');
}
@@ -33,7 +55,7 @@ class SyncronizeController extends Controller
public function syncIndexIntegration(Request $request, $uuid){
$token = $request->get('token');
$res = $this->service_simbg->syncIndexIntegration($uuid, $token);
$res = $this->service_simbg->syncIndexIntegration($uuid);
return $res;
}
@@ -42,4 +64,9 @@ class SyncronizeController extends Controller
$res = $this->service_simbg->syncTaskDetailSubmit($uuid, $token);
return $res;
}
public function syncTaskAssignments($uuid){
$res = $this->service_simbg->syncTaskAssignments($uuid);
return $res;
}
}

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)
{
//
}
}

0
app/Http/Requests/Auth/LoginRequest.php Executable file → Normal file
View File

View File

@@ -0,0 +1,51 @@
<?php
namespace App\Http\Resources;
use Illuminate\Http\Request;
use Illuminate\Http\Resources\Json\JsonResource;
class BigdataResumeResource extends JsonResource
{
/**
* Transform the resource into an array.
*
* @return array<string, mixed>
*/
public function toArray(Request $request): array
{
return [
'id' => $this->id,
'import_datasource_id' => $this->import_datasource_id,
'potention_count' => (int) $this->potention_count,
'potention_sum' => number_format((float) $this->potention_sum, 2, ',', '.'),
'non_verified_count' => (int) $this->non_verified_count,
'non_verified_sum' => number_format((float) $this->non_verified_sum, 2, ',', '.'),
'verified_count' => (int) $this->verified_count,
'verified_sum' => number_format((float) $this->verified_sum, 2, ',', '.'),
'business_count' => (int) $this->business_count,
'business_sum' => number_format((float) $this->business_sum, 2, ',', '.'),
'non_business_count' => (int) $this->non_business_count,
'non_business_sum' => number_format((float) $this->non_business_sum, 2, ',', '.'),
'spatial_count' => (int) $this->spatial_count,
'spatial_sum' => number_format((float) $this->spatial_sum, 2, ',', '.'),
'issuance_realization_pbg_count' => (int) $this->issuance_realization_pbg_count,
'issuance_realization_pbg_sum' => number_format((float) $this->issuance_realization_pbg_sum, 2, ',', '.'),
'waiting_click_dpmptsp_count' => (int) $this->waiting_click_dpmptsp_count,
'waiting_click_dpmptsp_sum' => number_format((float) $this->waiting_click_dpmptsp_sum, 2, ',', '.'),
'process_in_technical_office_count' => (int) $this->process_in_technical_office_count,
'process_in_technical_office_sum' => number_format((float) $this->process_in_technical_office_sum, 2, ',', '.'),
'year' => $this->year,
'created_at' => $this->created_at->toDateTimeString(),
];
}
}

View File

@@ -19,8 +19,8 @@ class DataSettingResource extends JsonResource
'key' => $this->key,
'value' => $this->value,
'type' => $this->type,
'created_at' => $this->created_at->toDateTimeString(),
'updated_at' => $this->updated_at->toDateTimeString(),
'created_at' => $this->created_at ? $this->created_at->toDateTimeString() : null,
'updated_at' => $this->updated_at ? $this->updated_at->toDateTimeString() : null,
];
}
}

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

@@ -3,37 +3,105 @@
namespace App\Imports;
use App\Models\BusinessOrIndustry;
use Maatwebsite\Excel\Concerns\ToModel;
use Maatwebsite\Excel\Concerns\ToCollection;
use Illuminate\Support\Collection;
use Maatwebsite\Excel\Concerns\ToCollection;
use Maatwebsite\Excel\Concerns\WithChunkReading;
use Maatwebsite\Excel\Concerns\WithHeadingRow;
use Maatwebsite\Excel\Concerns\WithMultipleSheets;
use Illuminate\Contracts\Queue\ShouldQueue;
use Maatwebsite\Excel\Concerns\WithBatchInserts;
use Illuminate\Support\Facades\Log;
class BusinessIndustriesImport implements ToCollection
class BusinessIndustriesImport implements ToCollection, WithMultipleSheets, WithChunkReading, WithBatchInserts, ShouldQueue, WithHeadingRow
{
/**
* @param array $row
*
* @return \Illuminate\Database\Eloquent\Model|null
*/
public function collection(Collection $rows)
* @param Collection $collection
*/
public function collection(Collection $collection)
{
foreach ($rows->skip(1) as $row){
$clean_nop = preg_replace('/[^A-Za-z0-9]/', '', $row[2]);
if (!BusinessOrIndustry::where('nop', $clean_nop)->exists()) {
BusinessOrIndustry::create([
'nama_kecamatan' => $row[0],
'nama_kelurahan' => $row[1],
'nop' => $clean_nop, // Store cleaned 'nop'
'nama_wajib_pajak' => $row[3],
'alamat_wajib_pajak' => $row[4],
'alamat_objek_pajak' => $row[5],
'luas_bumi' => $row[6],
'luas_bangunan' => $row[7],
'njop_bumi' => $row[8],
'njop_bangunan' => $row[9],
'ketetapan' => $row[10],
'tahun_pajak' => $row[11],
try{
$batchData = [];
$batchSize = 1000;
foreach ($collection as $row){
if(!isset($row['nop']) || empty($row['nop'])){
continue;
}
$clean_nop = preg_replace('/[^A-Za-z0-9]/', '', $row['nop']);
$batchData[] = [
'nama_kecamatan' => $row['nama_kecamatan'],
'nama_kelurahan' => $row['nama_kelurahan'],
'nop' => $clean_nop,
'nama_wajib_pajak' => $row['nama_wajib_pajak'],
'alamat_wajib_pajak' => $row['alamat_wajib_pajak'],
'alamat_objek_pajak' => $row['alamat_objek_pajak'],
'luas_bumi' => $row['luas_bumi'],
'luas_bangunan' => $row['luas_bangunan'],
'njop_bumi' => $row['njop_bumi'],
'njop_bangunan' => $row['njop_bangunan'],
'ketetapan' => $row['ketetapan'],
'tahun_pajak' => $row['tahun_pajak'],
];
if(count($batchData) >= $batchSize){
BusinessOrIndustry::upsert($batchData, ['nop'], [
'nama_kecamatan',
'nama_kelurahan',
'nama_wajib_pajak',
'alamat_wajib_pajak',
'alamat_objek_pajak',
'luas_bumi',
'luas_bangunan',
'njop_bumi',
'njop_bangunan',
'ketetapan',
'tahun_pajak',
]);
$batchData = [];
}
}
if(!empty($batchData)){
BusinessOrIndustry::upsert($batchData, ['nop'], [
'nama_kecamatan',
'nama_kelurahan',
'nama_wajib_pajak',
'alamat_wajib_pajak',
'alamat_objek_pajak',
'luas_bumi',
'luas_bangunan',
'njop_bumi',
'njop_bangunan',
'ketetapan',
'tahun_pajak',
]);
}
}catch(\Exception $exception){
Log::error('Error while importing Business Industries data:', ['error' => $exception->getMessage()]);
return;
}
}
public function sheets(): array {
return [
0 => $this
];
}
public function headingRow(): int
{
return 1;
}
public function chunkSize(): int
{
return 1000;
}
public function batchSize(): int
{
return 1000;
}
}

View File

@@ -11,32 +11,61 @@ use Maatwebsite\Excel\Concerns\WithHeadingRow;
use Maatwebsite\Excel\Concerns\WithMultipleSheets;
use Illuminate\Contracts\Queue\ShouldQueue;
use Maatwebsite\Excel\Concerns\WithBatchInserts;
use Illuminate\Support\Facades\Log;
class CustomersImport implements ToCollection, WithMultipleSheets
class CustomersImport implements ToCollection, WithMultipleSheets, WithChunkReading, WithBatchInserts, ShouldQueue, WithHeadingRow
{
/**
* @param Collection $collection
*/
*/
public function collection(Collection $collection)
{
$batchData = [];
$batchSize = 1000;
foreach ($collection->skip(1) as $row) {
if (!isset($row[0]) || empty($row[0])) {
foreach ($collection as $row) {
if (!isset($row['nomor_pelanggan']) || empty($row['nomor_pelanggan'])) {
continue;
}
$latitude = filter_var($row[4], FILTER_VALIDATE_FLOAT) ? bcadd($row[4], '0', 18) : null;
$longitude = filter_var($row[5], FILTER_VALIDATE_FLOAT) ? bcadd($row[5], '0', 18) : null;
$latitude = '0';
$longitude = '0';
if (isset($row['latkor']) && !empty(trim($row['latkor']))) {
$latitude = str_replace(',', '.', trim($row['latkor']));
if (is_numeric($latitude)) {
$latitude = bcadd($latitude, '0', 18);
} else {
$latitude = '0';
}
} else {
$latitude = '0';
}
if (isset($row['lonkor']) && !empty(trim($row['lonkor']))) {
$longitude = str_replace(',', '.', trim($row['lonkor']));
if (is_numeric($longitude)) {
$longitude = bcadd($longitude, '0', 18);
} else {
$longitude = '0';
}
} else {
$longitude = '0';
}
$batchData[] = [
'nomor_pelanggan' => $row[0],
'kota_pelayanan' => $row[1],
'nama' => $row[2],
'alamat' => $row[3],
'nomor_pelanggan' => $row['nomor_pelanggan'] ?? '',
'kota_pelayanan' => $row['kota_pelayanan'] ?? '',
'nama' => $row['nama'] ?? '',
'alamat' => $row['alamat'] ?? '',
'latitude' => $latitude,
'longitude' => $longitude,
];
if (count($batchData) >= $batchSize) {
Customer::upsert($batchData, ['nomor_pelanggan'], ['kota_pelayanan', 'nama', 'alamat', 'latitude', 'longitude']);
$batchData = [];
}
}
if (!empty($batchData)) {
@@ -44,9 +73,20 @@ class CustomersImport implements ToCollection, WithMultipleSheets
}
}
public function sheets(): array {
return [
0 => $this
];
}
public function chunkSize(): int
{
return 1000;
}
public function batchSize(): int
{
return 1000;
}
}

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

@@ -0,0 +1,80 @@
<?php
namespace App\Jobs;
use App\Models\ImportDatasource;
use App\Services\GoogleSheetService;
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;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Queue\SerializesModels;
class SyncronizeSIMBG implements ShouldQueue
{
use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;
public $tries = 1;
public function __construct()
{
// Avoid injecting non-serializable dependencies here
}
public function handle(): void
{
$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

@@ -21,6 +21,15 @@ class BigdataResume extends Model
'business_sum',
'non_business_count',
'non_business_sum',
'spatial_count',
'spatial_sum',
'year',
'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',
];
public function importDatasource()
@@ -28,88 +37,84 @@ class BigdataResume extends Model
return $this->belongsTo(ImportDatasource::class, 'import_datasource_id');
}
public static function generateResumeData($import_datasource_id){
$query_verified = once( function () {
return DB::table('pbg_task AS pt')
->leftJoin('pbg_task_google_sheet AS ptgs', 'pt.registration_number', '=', 'ptgs.no_registrasi')
->leftJoin('pbg_task_retributions AS ptr', 'pt.uuid', '=', 'ptr.pbg_task_uid')
->whereRaw('LOWER(TRIM(ptgs.status_verifikasi)) = ?', [strtolower(trim('Selesai Verifikasi'))])
->selectRaw('COUNT(pt.id) AS total_data,
SUM(ptr.nilai_retribusi_bangunan) AS total_retribution')
->first();
});
$verified_count = $query_verified->total_data ?? 0;
$verified_total = $query_verified->total_retribution ?? 0;
$query_business = once(function () {
return DB::table('pbg_task AS pt')
->leftJoin('pbg_task_google_sheet AS ptgs', 'pt.registration_number', '=', 'ptgs.no_registrasi')
->leftJoin('pbg_task_retributions AS ptr', 'pt.uuid', '=', 'ptr.pbg_task_uid')
->where(function ($query) {
$query->whereRaw('LOWER(TRIM(ptgs.status_verifikasi)) != ?', [strtolower(trim('Selesai Verifikasi'))])
->orWhereNull('ptgs.status_verifikasi');
})
->where(function ($query) {
$query->whereRaw('LOWER(TRIM(pt.function_type)) = ?', [strtolower(trim('Sebagai Tempat Usaha'))]);
})
->selectRaw('COUNT(pt.id) AS total_data,
SUM(ptr.nilai_retribusi_bangunan) AS total_retribution')
->first();
});
$business_count = $query_business->total_data ?? 0;
$business_total = $query_business->total_retribution ?? 0;
$query_non_business = once( function () {
return DB::table('pbg_task AS pt')
->leftJoin('pbg_task_google_sheet AS ptgs', 'pt.registration_number', '=', 'ptgs.no_registrasi')
->leftJoin('pbg_task_retributions AS ptr', 'pt.uuid', '=', 'ptr.pbg_task_uid') // Join ke pbg_task_retributions
->where(function ($query) {
$query->whereRaw('LOWER(TRIM(ptgs.status_verifikasi)) != ?', [strtolower(trim('Selesai Verifikasi'))])
->orWhereNull('ptgs.status_verifikasi'); // Include NULL values
public static function generateResumeData($import_datasource_id, $year, $data_setting){
$stats = PbgTask::with(['googleSheet', 'pbg_task_retributions'])
->leftJoin('pbg_task_retributions as ptr', 'pbg_task.uuid', '=', 'ptr.pbg_task_uid')
->leftJoin('pbg_task_google_sheet as ptgs', 'pbg_task.registration_number', '=', 'ptgs.no_registrasi')
->when($year !== 'all', function ($query) use ($year) {
$query->whereYear('pbg_task.task_created_at', (int) $year);
})
->where(function ($query) {
$query->whereRaw('LOWER(TRIM(pt.function_type)) != ?', [strtolower(trim('Sebagai Tempat Usaha'))])
->orWhereNull('pt.function_type'); // Include NULL values
})
->selectRaw('COUNT(pt.id) AS total_data,
SUM(ptr.nilai_retribusi_bangunan) AS total_retribution') // Menambahkan SUM dari pbg_task_retributions
->first();
});
$non_business_count = $query_non_business->total_data ?? 0;
$non_business_total = $query_non_business->total_retribution ?? 0;
->selectRaw("
COUNT(CASE WHEN LOWER(TRIM(ptgs.status_verifikasi)) = 'selesai verifikasi' THEN 1 END) AS verified_count,
SUM(CASE WHEN LOWER(TRIM(ptgs.status_verifikasi)) = 'selesai verifikasi' THEN ptr.nilai_retribusi_bangunan ELSE 0 END) AS verified_total,
COUNT(CASE WHEN LOWER(TRIM(ptgs.status_verifikasi)) != 'selesai verifikasi' OR ptgs.status_verifikasi IS NULL THEN 1 END) AS non_verified_count,
SUM(CASE WHEN LOWER(TRIM(ptgs.status_verifikasi)) != 'selesai verifikasi' OR ptgs.status_verifikasi IS NULL THEN ptr.nilai_retribusi_bangunan ELSE 0 END) AS non_verified_total,
COUNT(CASE WHEN (LOWER(TRIM(ptgs.status_verifikasi)) != 'selesai verifikasi' OR ptgs.status_verifikasi IS NULL)
AND LOWER(TRIM(pbg_task.function_type)) = 'sebagai tempat usaha' THEN 1 END) AS business_count,
SUM(CASE WHEN (LOWER(TRIM(ptgs.status_verifikasi)) != 'selesai verifikasi' OR ptgs.status_verifikasi IS NULL)
AND LOWER(TRIM(pbg_task.function_type)) = 'sebagai tempat usaha' THEN ptr.nilai_retribusi_bangunan ELSE 0 END) AS business_total,
$query_non_verified = once(function () {
return DB::table('pbg_task AS pt')
->leftJoin('pbg_task_google_sheet AS ptgs', 'pt.registration_number', '=', 'ptgs.no_registrasi')
->leftJoin('pbg_task_retributions AS ptr', 'pt.uuid', '=', 'ptr.pbg_task_uid') // Join tabel pbg_task_retributions
->where(function ($query) {
$query->whereRaw('LOWER(TRIM(ptgs.status_verifikasi)) != ?', [strtolower(trim('Selesai Verifikasi'))])
->orWhereNull('ptgs.status_verifikasi'); // Include NULL values
})
->selectRaw('COUNT(pt.id) AS total_data,
SUM(ptr.nilai_retribusi_bangunan) AS total_retribution') // Menambahkan SUM dari pbg_task_retributions
COUNT(CASE WHEN (LOWER(TRIM(ptgs.status_verifikasi)) != 'selesai verifikasi' OR ptgs.status_verifikasi IS NULL)
AND (LOWER(TRIM(pbg_task.function_type)) != 'sebagai tempat usaha' OR pbg_task.function_type IS NULL) THEN 1 END) AS non_business_count,
SUM(CASE WHEN (LOWER(TRIM(ptgs.status_verifikasi)) != 'selesai verifikasi' OR ptgs.status_verifikasi IS NULL)
AND (LOWER(TRIM(pbg_task.function_type)) != 'sebagai tempat usaha' OR pbg_task.function_type IS NULL) THEN ptr.nilai_retribusi_bangunan ELSE 0 END) AS non_business_total
")
->first();
// Assign Results
$verified_count = $stats->verified_count ?? 0;
$verified_total = $stats->verified_total ?? 0;
$non_verified_count = $stats->non_verified_count ?? 0;
$non_verified_total = $stats->non_verified_total ?? 0;
$business_count = $stats->business_count ?? 0;
$business_total = $stats->business_total ?? 0;
$non_business_count = $stats->non_business_count ?? 0;
$non_business_total = $stats->non_business_total ?? 0;
$query_potention = once(function () use ($year) {
$query = PbgTask::leftJoin('pbg_task_retributions as ptr', 'pbg_task.uuid', '=', 'ptr.pbg_task_uid')
->selectRaw('COUNT(DISTINCT pbg_task.id) as task_count, SUM(ptr.nilai_retribusi_bangunan) as total_retribution');
if ($year !== 'all') {
$query->whereYear('pbg_task.task_created_at', (int) $year);
}
return $query->first();
});
$non_verified_count = $query_non_verified->total_data ?? 0;
$non_verified_total = $query_non_verified->total_retribution ?? 0;
$query_potention = once( function () {
return DB::table('pbg_task as pt')
->leftJoin('pbg_task_retributions as ptr', 'pt.uuid', '=', 'ptr.pbg_task_uid')
->select(
DB::raw('COUNT(DISTINCT pt.id) as task_count'),
DB::raw('SUM(ptr.nilai_retribusi_bangunan) as total_retribution')
)
->first();
});
$potention_count = $query_potention->task_count ?? 0;
$potention_total = $query_potention->total_retribution ?? 0;
$query_spatial_plannings = once(function () use ($year) {
$query = PbgTask::leftJoin('spatial_plannings as sp', 'pbg_task.document_number', '=', 'sp.number')
->leftJoin('pbg_task_retributions as ptr', 'ptr.pbg_task_uid', '=', 'pbg_task.uuid')
->selectRaw('
CASE
WHEN COUNT(DISTINCT sp.id) > 0 THEN COUNT(DISTINCT sp.id)
ELSE (SELECT COUNT(*) FROM spatial_plannings)
END as task_count,
SUM(CASE WHEN sp.id IS NOT NULL AND ptr.id IS NOT NULL THEN ptr.nilai_retribusi_bangunan ELSE 0 END) as total_retribution
');
if ($year !== 'all') {
$query->whereYear('pbg_task.task_created_at', (int) $year);
}
return $query->first();
});
$spatial_planning_count = $query_spatial_plannings->task_count ?? 0;
$spatial_planning_total = $query_spatial_plannings->total_retribution;
$potention_count -= $spatial_planning_count;
$potention_total -= $spatial_planning_total;
return self::create([
'import_datasource_id' => $import_datasource_id,
'spatial_count' => $spatial_planning_count,
'spatial_sum' => $spatial_planning_total ?? 0.00,
'potention_count' => $potention_count ?? 0,
'potention_sum' => $potention_total ?? 0.00,
'non_verified_count' => $non_verified_count ?? 0,
@@ -120,6 +125,13 @@ class BigdataResume extends Model
'business_sum' => $business_total ?? 0.00,
'non_business_count' => $non_business_count ?? 0,
'non_business_sum' => $non_business_total ?? 0.00,
'year' => $year,
'waiting_click_dpmptsp_count' => $data_setting['MENUNGGU_KLIK_DPMPTSP_COUNT'] ?? 0,
'waiting_click_dpmptsp_sum' => $data_setting['MENUNGGU_KLIK_DPMPTSP_SUM'] ?? 0.00,
'issuance_realization_pbg_count' => $data_setting['REALISASI_TERBIT_PBG_COUNT'] ?? 0,
'issuance_realization_pbg_sum' => $data_setting['REALISASI_TERBIT_PBG_SUM'] ?? 0.00,
'process_in_technical_office_count' => $data_setting['PROSES_DINAS_TEKNIS_COUNT'] ?? 0,
'process_in_technical_office_sum' => $data_setting['PROSES_DINAS_TEKNIS_SUM'] ??0.00,
]);
}
}

View File

@@ -0,0 +1,167 @@
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsTo;
use Illuminate\Database\Eloquent\Relations\HasOne;
use Illuminate\Database\Eloquent\Relations\HasMany;
class BuildingFunction extends Model
{
protected $table = 'building_functions';
protected $fillable = [
'code',
'name',
'description',
'parent_id',
'level',
'sort_order',
'base_tariff'
];
protected $casts = [
'level' => 'integer',
'sort_order' => 'integer',
'base_tariff' => 'decimal:2'
];
/**
* Parent relationship (self-referencing)
*/
public function parent(): BelongsTo
{
return $this->belongsTo(BuildingFunction::class, 'parent_id');
}
/**
* Children relationship (self-referencing)
*/
public function children(): HasMany
{
return $this->hasMany(BuildingFunction::class, 'parent_id')
->orderBy('sort_order');
}
/**
* Parameters relationship (1:1)
*/
public function parameter(): HasOne
{
return $this->hasOne(BuildingFunctionParameter::class);
}
/**
* Formulas relationship (1:n) - multiple formulas for different floor numbers
*/
public function formulas(): HasMany
{
return $this->hasMany(RetributionFormula::class)->orderBy('floor_number');
}
/**
* Get appropriate formula based on floor number
*/
public function getFormulaForFloor(int $floorNumber): ?RetributionFormula
{
return $this->formulas()
->where('floor_number', $floorNumber)
->first();
}
/**
* Retribution proposals relationship (1:n)
*/
public function retributionProposals(): HasMany
{
return $this->hasMany(RetributionProposal::class, 'building_function_id');
}
/**
* Scope: Parent functions only
*/
public function scopeParents($query)
{
return $query->whereNull('parent_id');
}
/**
* Scope: Children functions only
*/
public function scopeChildren($query)
{
return $query->whereNotNull('parent_id');
}
/**
* Scope: By level
*/
public function scopeByLevel($query, int $level)
{
return $query->where('level', $level);
}
/**
* Check if building function has complete setup (parameters + at least one formula)
*/
public function hasCompleteSetup(): bool
{
return $this->parameter()->exists() && $this->formulas()->exists();
}
/**
* Get building function with all related data
*/
public function getCompleteData(): array
{
return [
'id' => $this->id,
'code' => $this->code,
'name' => $this->name,
'description' => $this->description,
'level' => $this->level,
'sort_order' => $this->sort_order,
'base_tariff' => $this->base_tariff,
'parameters' => $this->parameter?->getParametersArray(),
'formulas' => $this->formulas->map(function ($formula) {
return [
'id' => $formula->id,
'name' => $formula->name,
'expression' => $formula->formula_expression,
'floor_number' => $formula->floor_number,
'floor_description' => $this->getFloorDescription($formula->floor_number)
];
})->toArray(),
'has_complete_setup' => $this->hasCompleteSetup()
];
}
/**
* Get floor description
*/
public function getFloorDescription(?int $floorNumber): string
{
if ($floorNumber === null || $floorNumber === 0) {
return 'Semua lantai';
}
return "Lantai {$floorNumber}";
}
/**
* Check if this is a parent function
*/
public function isParent(): bool
{
return $this->parent_id === null;
}
/**
* Check if this is a child function
*/
public function isChild(): bool
{
return $this->parent_id !== null;
}
}

View File

@@ -0,0 +1,110 @@
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
class BuildingFunctionFormulaConfig extends Model
{
use HasFactory;
protected $fillable = [
'building_function_id',
'formula_id',
'floor_level',
'min_floor',
'max_floor',
'multiplier',
'is_active',
'priority',
'notes',
];
protected $casts = [
'multiplier' => 'decimal:4',
'is_active' => 'boolean',
'min_floor' => 'integer',
'max_floor' => 'integer',
'floor_level' => 'integer',
'priority' => 'integer',
];
/**
* Relationship to BuildingFunction
*/
public function buildingFunction()
{
return $this->belongsTo(BuildingFunction::class, 'building_function_id');
}
/**
* Relationship to MasterFormula
*/
public function formula()
{
return $this->belongsTo(MasterFormula::class, 'formula_id');
}
/**
* Scope untuk konfigurasi aktif
*/
public function scopeActive($query)
{
return $query->where('is_active', true);
}
/**
* Scope untuk mencari berdasarkan building function dan floor level
*/
public function scopeForBuildingAndFloor($query, $buildingFunctionId, $floorLevel)
{
return $query->where('building_function_id', $buildingFunctionId)
->where(function($q) use ($floorLevel) {
$q->where('floor_level', $floorLevel)
->orWhere('floor_level', 0) // 0 = berlaku untuk semua lantai
->orWhere(function($qq) use ($floorLevel) {
$qq->whereNotNull('min_floor')
->whereNotNull('max_floor')
->where('min_floor', '<=', $floorLevel)
->where('max_floor', '>=', $floorLevel);
});
})
->orderBy('priority', 'desc')
->orderBy('floor_level', 'desc'); // Prioritas: spesifik floor > range > semua lantai
}
/**
* Method untuk mendapatkan formula yang tepat untuk building function dan floor tertentu
*/
public static function getFormulaForBuildingAndFloor($buildingFunctionId, $floorLevel)
{
return self::active()
->forBuildingAndFloor($buildingFunctionId, $floorLevel)
->with('formula')
->first();
}
/**
* Method untuk check apakah floor level masuk dalam range
*/
public function isFloorInRange($floorLevel)
{
// Jika floor_level = 0, berlaku untuk semua lantai
if ($this->floor_level == 0) {
return true;
}
// Jika ada specific floor level
if ($this->floor_level == $floorLevel) {
return true;
}
// Jika ada range min-max
if (!is_null($this->min_floor) && !is_null($this->max_floor)) {
return $floorLevel >= $this->min_floor && $floorLevel <= $this->max_floor;
}
return false;
}
}

View File

@@ -0,0 +1,134 @@
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsTo;
class BuildingFunctionParameter extends Model
{
protected $fillable = [
'building_function_id',
'fungsi_bangunan',
'ip_permanen',
'ip_kompleksitas',
'indeks_lokalitas',
'asumsi_prasarana',
'koefisien_dasar',
'faktor_penyesuaian',
'custom_parameters',
'parameter_notes'
];
protected $casts = [
'fungsi_bangunan' => 'decimal:6',
'ip_permanen' => 'decimal:6',
'ip_kompleksitas' => 'decimal:6',
'indeks_lokalitas' => 'decimal:6',
'asumsi_prasarana' => 'decimal:6',
'koefisien_dasar' => 'decimal:6',
'faktor_penyesuaian' => 'decimal:6',
'custom_parameters' => 'array'
];
/**
* Building function relationship (1:1)
*/
public function buildingFunction(): BelongsTo
{
return $this->belongsTo(BuildingFunction::class);
}
/**
* Scope: Active parameters only
*/
public function scopeActive($query)
{
return $query->where('is_active', true);
}
/**
* Get all parameter values as array
*/
public function getParametersArray(): array
{
return [
'fungsi_bangunan' => $this->fungsi_bangunan,
'ip_permanen' => $this->ip_permanen,
'ip_kompleksitas' => $this->ip_kompleksitas,
'indeks_lokalitas' => $this->indeks_lokalitas,
'asumsi_prasarana' => $this->asumsi_prasarana,
'koefisien_dasar' => $this->koefisien_dasar,
'faktor_penyesuaian' => $this->faktor_penyesuaian,
'custom_parameters' => $this->custom_parameters
];
}
/**
* Get formatted parameters for display
*/
public function getFormattedParameters(): array
{
return [
'Fungsi Bangunan' => $this->fungsi_bangunan,
'IP Permanen' => $this->ip_permanen,
'IP Kompleksitas' => $this->ip_kompleksitas,
'Indeks Lokalitas' => $this->indeks_lokalitas,
'Asumsi Prasarana' => $this->asumsi_prasarana,
'Koefisien Dasar' => $this->koefisien_dasar,
'Faktor Penyesuaian' => $this->faktor_penyesuaian
];
}
/**
* Calculate floor result using the main formula
*/
public function calculateFloorResult(float $ipKetinggian): float
{
return $this->fungsi_bangunan * (
$this->ip_permanen +
$this->ip_kompleksitas +
(0.5 * $ipKetinggian)
);
}
/**
* Calculate full retribution for given building area and floor result
*/
public function calculateRetribution(float $luasBangunan, float $floorResult): float
{
$baseValue = 70350; // Base retribution value
$mainCalculation = 1 * $luasBangunan * ($this->indeks_lokalitas * $baseValue * $floorResult * 1);
$additionalCalculation = 0.5 * $mainCalculation;
return $mainCalculation + $additionalCalculation;
}
/**
* Apply custom parameters if available
*/
public function getParameterValue(string $key, $default = null)
{
// First check if it's a standard parameter
if (property_exists($this, $key) && $this->$key !== null) {
return $this->$key;
}
// Then check custom parameters
if ($this->custom_parameters && is_array($this->custom_parameters)) {
return $this->custom_parameters[$key] ?? $default;
}
return $default;
}
/**
* Set custom parameter
*/
public function setCustomParameter(string $key, $value): void
{
$customParams = $this->custom_parameters ?? [];
$customParams[$key] = $value;
$this->custom_parameters = $customParams;
}
}

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