126 Commits

Author SHA1 Message Date
ismailmasseran b52f4b6919 Merge pull request 'DONE: add password on laravel log viewer' (#19) from feature/add-pass-logviewer into main
Build Docker Image / build-backend (push) Successful in 18s
Reviewed-on: #19
2026-09-28 16:27:55 +08:00
ISMAIL MASSERAN b8e3e2b369 DONE: add password on laravel log viewer 2026-09-28 16:26:50 +08:00
ismailmasseran 3a86ba5b26 Merge pull request 'DONE: add env based checking for whatsapp before testing at staging' (#18) from feature/env-based-whatsapp-cloud into main
Build Docker Image / build-backend (push) Successful in 18s
Reviewed-on: #18
2026-09-28 10:30:11 +08:00
ISMAIL MASSERAN b1934e1627 DONE: add env based checking for whatsapp before testing at staging 2026-09-28 10:26:06 +08:00
ISMAIL MASSERAN 583d936fd2 DONE: update whatsapp message template
Build Docker Image / build-backend (push) Successful in 17s
2026-09-27 15:57:50 +08:00
ISMAIL MASSERAN 1076ecbaf2 DONE: update env.staging
Build Docker Image / build-backend (push) Successful in 26s
2026-09-26 18:51:47 +08:00
ismailmasseran 92894bad44 Merge pull request 'fix: change pembiayaan online batch 2 cutoff from 16:30 to 15:00' (#17) from fix/pembiayaan-online-batch2-cutoff into main
Reviewed-on: #17
2026-09-24 16:15:43 +08:00
nurafrinaalimi16 9916e81dba fix: change pembiayaan online batch 2 cutoff from 16:30 to 15:00 2026-09-24 16:14:44 +08:00
ismailmasseran 7fb7f75050 Feature/whatsapp blast (#16)
Build Docker Image / build-backend (push) Successful in 18s
Co-authored-by: ISMAIL MASSERAN <topaz@Mac.dlinkrouter.local>
Co-authored-by: ISMAIL MASSERAN <topaz@ISMAILs-Macbook.local>
Reviewed-on: #16
2026-09-24 11:27:48 +08:00
ismailmasseran 9fa0172017 Experiment/merge annur (#15)
Build Docker Image / build-backend (push) Successful in 23s
Co-authored-by: ISMAIL MASSERAN <topaz@Mac.dlinkrouter.local>
Reviewed-on: #15
2026-09-20 12:49:53 +08:00
ismailmasseran 79bc41d211 Merge pull request 'feature: include cara terima in reports' (#14) from feature/tagging-cara-terima into main
Reviewed-on: #14
2026-09-20 09:38:22 +08:00
nurafrinaalimi16 2f6f06d3e3 feature: include cara terima in reports 2026-09-17 16:23:46 +08:00
ismailmasseran 8de9d872f9 Merge pull request 'feature/modal-online-pendahuluan' (#13) from feature/modal-online-pendahuluan into main
Reviewed-on: #13
2026-09-17 07:58:26 +08:00
nurafrinaalimi16 20268cd136 feature/modal-online-pendahuluan 2026-09-14 15:26:35 +08:00
nurafrinaalimi16 aa4c8ca5ba fix laporan barang kes controller 2026-09-10 09:27:57 +08:00
ismailmasseran 7920eb9f71 Explore/ismail (#12)
Build Docker Image / build-backend (push) Successful in 10s
Co-authored-by: ISMAIL MASSERAN <topaz@ISMAILs-Macbook.local>
Co-authored-by: ISMAIL MASSERAN <topaz@Mac.dlinkrouter.local>
Reviewed-on: #12
Co-authored-by: ismailmasseran <ismail@koppkb.com>
Co-committed-by: ismailmasseran <ismail@koppkb.com>
2026-09-09 14:47:33 +08:00
afrina 5fc212f6af Prod kopkb (#8)
Co-authored-by: nurafrinaalimi16 <nurafrinaalimi16@gmail.com>
Co-authored-by: dev_kopkb <xtrabiz.sb@gmail.com>
Co-authored-by: root <root@erahn.click>
Reviewed-on: #8
Co-authored-by: afrina <afrina@koppkb.com>
Co-committed-by: afrina <afrina@koppkb.com>
2026-09-01 15:09:35 +08:00
ismailmasseran 51860cea37 DONE: add cicd for api_arrahn (#2)
Build Docker Image / build-backend (push) Successful in 8s
Co-authored-by: ISMAIL MASSERAN <topaz@ISMAILs-Macbook.local>
Reviewed-on: #2
2026-08-26 12:03:29 +08:00
afrina f1618c1ffd Rebate anggota (#1)
Co-authored-by: nurafrinaalimi16 <nurafrinaalimi16@gmail.com>
Reviewed-on: #1
2026-08-26 11:40:55 +08:00
nurafrinaalimi16 162f246acc function wtd baru 2026-08-03 12:43:55 +08:00
nurafrinaalimi16 95997841cf Merge remote-tracking branch 'origin/rebate-anggota' into rebate-anggota 2026-06-14 15:58:31 +08:00
nurafrinaalimi16 9ff4393313 include kplama on report marhun 2026-06-14 15:38:38 +08:00
nurafrinaalimi16 5bc5d286b4 fix figure on laporan terkumpul 2026-06-14 15:37:58 +08:00
nurafrinaalimi16 5826f92661 pdpa for koperasi 2026-06-14 15:37:25 +08:00
nurafrinaalimi16 6961697298 include lahad datu on report stok audit 2026-06-14 15:36:33 +08:00
nurafrinaalimi16 482fbbd17e fix bilangan pelanggan baru on report terkumpul 2026-06-14 15:36:33 +08:00
nurafrinaalimi16 cd83999045 disable logs kadar anggota 2026-06-14 15:36:33 +08:00
nurafrinaalimi16 e8da816f35 put excpetion if kadar upah = 0 2026-06-14 15:36:33 +08:00
nurafrinaalimi16 39a2f9a5ef fix kadar upah return 0 2026-06-14 15:36:33 +08:00
nurafrinaalimi16 cc11e3aed6 add column name on operasi approval 2026-06-14 15:36:33 +08:00
nurafrinaalimi16 c7874c15bc fix error url lelong 2026-06-14 15:36:33 +08:00
nurafrinaalimi16 e7650febfc fix url lelong 2026-06-14 15:36:32 +08:00
nurafrinaalimi16 0b1c50676e comment command import csv 2026-06-14 15:36:32 +08:00
nurafrinaalimi16 db9b17f369 import csv anggota koperasi 2026-06-14 15:36:32 +08:00
nurafrinaalimi16 15a3972ae9 route for kadar anggota 2026-06-14 15:36:32 +08:00
nurafrinaalimi16 1717035643 database migration for kadar anggota koperasi 2026-06-14 15:36:32 +08:00
nurafrinaalimi16 a3cb756f6b calculation for kadar anggota koperasi 2026-06-14 15:36:32 +08:00
nurafrinaalimi16 fed2cfea72 update all controllers for kadar anggota koperasi 2026-06-14 15:36:32 +08:00
nurafrinaalimi16 0358878e83 models for kadar anggota koperasi 2026-06-14 15:14:02 +08:00
nurafrinaalimi16 2fa36eabf7 include kplama on report marhun 2026-06-14 15:06:24 +08:00
nurafrinaalimi16 237a5aa44b fix figure on laporan terkumpul 2026-06-14 15:05:02 +08:00
nurafrinaalimi16 e1878e31e4 pdpa for koperasi 2026-06-14 15:02:45 +08:00
Muhd hafifie b669d3f04a Merged in feature/margin-hargaemas-v2 (pull request #408)
Feature/margin hargaemas v2
2026-04-19 07:27:54 +00:00
Hafifie PKB 0dcf421d0e added laporan audit in operasi 2026-04-19 15:10:26 +08:00
Hafifie PKB c76fce70c3 added audit logs for operasi 2026-04-19 15:09:16 +08:00
Hafifie PKB 860b57285d added nilaimarhun for marign teller and pc 2026-04-19 15:09:16 +08:00
Hafifie PKB d540a3461d add validation for editing mutu marhun 2026-04-19 15:09:16 +08:00
Hafifie PKB 041369e049 add specific mutuemas API 2026-04-19 15:09:16 +08:00
Hafifie PKB ab598c12c9 1. added page for edit mutu
2. change from max pinjaman with a static 75% and 80% to manipulate value
2026-04-19 15:09:16 +08:00
nurulnisha muhammad 441a39b80f Merged in fixbugs-wtd-process (pull request #406)
fixbugs-wtd-process
2026-04-12 08:26:57 +00:00
Nisha Muhd 00ee7be836 fixbugs-wtd-process 2026-04-12 12:46:38 +08:00
izzati zulkifli 4eb86b8f27 Merged in izzati-addfeat-laporan-outstanding-v2 (pull request #401)
tambah baik laporan stok audit keseluruhan
2026-02-23 07:26:30 +00:00
Nur Izzati 522727159f tambah baik laporan stok audit keseluruhan 2026-02-23 15:25:29 +08:00
izzati zulkifli 014b49f571 Merged in izzati-addfeat-laporan-outstanding-v2 (pull request #400)
update laporan peti besi
2026-02-22 07:32:01 +00:00
Nur Izzati df734c2482 update laporan peti besi 2026-02-22 15:31:11 +08:00
izzati zulkifli b70bd7ce51 Merged in izzati-addfeat-laporan-outstanding-v2 (pull request #398)
tambah field barang kes dalam laporan outstanding
2026-02-22 06:13:52 +00:00
Nur Izzati edcc0dc0d4 tambah field barang kes dalam laporan outstanding 2026-02-22 14:13:19 +08:00
izzati zulkifli a337b6cfa4 Merged in izzati-feat-uum-bycaw-v2 (pull request #396)
update tast uum bycaw
2026-02-10 02:45:44 +00:00
Nur Izzati a4b235511b update tast uum bycaw 2026-02-10 10:42:18 +08:00
Ain Izazi dbbc18516e fix report petibesi 2026-02-02 12:48:59 +08:00
Ain Izazi 96d70bf2a9 fix report gadaian v2 not sync with v3 2026-02-02 10:44:02 +08:00
izzati zulkifli 6ba62cc7f8 Merged in izzati-hotfix-laporan-lelong-hargaasas (pull request #393)
update lelong keseleuruhan
2026-01-27 08:56:03 +00:00
Nur Izzati 53be2d999e update lelong keseleuruhan 2026-01-27 16:52:00 +08:00
arrahn pkb a28881824f Merged in krk-production (pull request #392)
Add krk changes to prod
2026-01-20 03:44:16 +00:00
Afiq Hamzah 288c10bcc6 Restore composer.json and composer.lock from production 2026-01-20 11:42:43 +08:00
Afiq Hamzah 8fe42c1d9f Refactor tenant database configuration to use dynamic config values
- Replace hardcoded database names (online_arrahn, master_krk, kaunterpkb)
  with configurable values across the codebase
- Rename tennant_master.php to tennant_database.php for clearer naming
- Update config keys: 'database' → 'master_db', add 'kaunter_db'
- Update env variables: TENNANT_MASTER_DB and TENNANT_KAUNTER_DB
- Modify Helper.php to use dynamic database references in
  getOnlineArrahnConnection(), getActiveCawanganDbConnection(),
  and getInactiveCawanganDbConnection() methods
- Update database JOIN queries in CustomerController and MarhunController
  to use config values instead of hardcoded database names
- Simplify migration logic by removing redundant hardcoded database checks
- Update debug messages in CawanganDebugConnections to show actual
  configured database name
- Update bootstrap/app.php to load tennant_database config

This change improves multi-environment flexibility and eliminates
environment-specific hardcoded values, making the application more
configurable for different deployment scenarios (KRK, KGMK, etc).
2026-01-20 11:36:41 +08:00
Afiq Hamzah 0ac42331d4 Add krk changes to prod 2026-01-19 16:41:10 +08:00
izzati zulkifli eae7a0e91a Merged in izzati-hotfix-uum (pull request #390)
update code outstanding
2026-01-18 00:48:34 +00:00
Nur Izzati 7f1a42a4cd update code outstanding 2026-01-18 08:44:37 +08:00
nurulnisha muhammad 1d6ca71ce1 Merged in feature/nisha/checking-wtd (pull request #389)
nisha-checking-wtd
2026-01-15 07:07:55 +00:00
Nisha Muhd ec72c708cd nisha-checking-wtd 2026-01-15 13:07:11 +08:00
izzati zulkifli 1d2c2ed59f Merged in izzati-hotfix-uum (pull request #388)
update nopelanggan dalam task uum
2026-01-15 04:34:56 +00:00
Nur Izzati 302519d723 update nopelanggan dalam task uum 2026-01-15 12:30:25 +08:00
izzati zulkifli f30cdc4d14 Merged in izzati-feat-uum (pull request #385)
update code status aktif pelanggan
2026-01-14 07:36:27 +00:00
Nur Izzati 133d508625 update code status aktif pelanggan 2026-01-14 15:35:29 +08:00
izzati zulkifli 5ac3484199 Merged in izzati-feat-uum (pull request #384)
update task uum
2026-01-14 01:26:34 +00:00
Nur Izzati 8756def2cf update task uum 2026-01-14 09:25:57 +08:00
nurulnisha muhammad 9e25c4a483 Merged in feature/nisha/laporan-wtd (pull request #383)
laporan_rumusan_wtd
2026-01-06 07:52:08 +00:00
Nisha Muhd 2aff962981 laporan_rumusan_wtd 2026-01-06 12:52:02 +08:00
nurulnisha muhammad ccd7447276 Merged in feature/nisha-update-wtd (pull request #378)
update wtd
2025-12-21 03:17:10 +00:00
BTMS3 3a8e74c368 update wtd 2025-12-21 11:15:57 +08:00
nur amirah zulkipli 573ad8a23f Merged in feature/saringan-gadaian-kb1 (pull request #377)
Add reporting saringan gadaian kb1
2025-12-15 03:10:22 +00:00
Amirah e983374a90 Add reporting saringan gadaian kb1 2025-12-15 11:09:24 +08:00
izzati zulkifli 8cce0193b0 Merged in izzati-hotfix-laporan-SA-all (pull request #372)
tambah list laporan SA lelong_tawarruq = 0
2025-11-26 08:35:29 +00:00
Nur Izzati e8e94c714b tambah list laporan SA lelong_tawarruq = 0 2025-11-26 16:35:07 +08:00
Muhd hafifie 67d990ab57 Merged in feature/customerlelong-v2 (pull request #370)
fix certain for sttebus = 'L' only
2025-11-15 15:31:01 +00:00
Hafifie PKB a1f3bc29f5 fix certain for sttebus = 'L' only 2025-11-15 23:23:14 +08:00
izzati zulkifli fb2726eacc Merged in izzati-lelong-batu-permata (pull request #366)
update lelong batu permata
2025-10-30 03:36:17 +00:00
Nur Izzati 0184a0f3e1 update lelong batu permata 2025-10-30 11:16:16 +08:00
Aiman Mazlan 9fdeb7ae4f Merged in feature/aiman/laporan-aliran-tunai-teller (pull request #365)
Feature/aiman/laporan aliran tunai teller

Approved-by: Muhd hafifie
2025-10-27 07:56:14 +00:00
aiman ece4210134 Filter bakiLelong by kodlaluan teller 2025-10-15 14:55:26 +08:00
aiman a42d36f69b Enable datepicker, new route for laporan aliran tunai teller 2025-10-14 15:55:24 +08:00
aiman 04bc76ef89 Add Baki Lelong for laporan aliran tunai teller 2025-10-12 12:38:00 +08:00
Ain Izazi Aziz de65d4d4fd Merged in hotfixreportbrgkes (pull request #363)
add radio button for report brg kes
2025-10-12 03:53:14 +00:00
Ain Izazi d21ad0f129 add radio button for report brg kes 2025-10-12 11:52:18 +08:00
izzati zulkifli f756e3b791 Merged in izzati-hotfix-tlelong-dlm-gadai (pull request #361)
update export lelong to api
2025-10-07 08:10:40 +00:00
Nur Izzati a8b63af59f update export lelong to api 2025-10-07 15:47:29 +08:00
Afiq Hamzah bfb3af49c8 Remove duplicated methods 2025-10-05 16:48:39 +08:00
Afiq Hamzah c80a676429 Resolve remaining merge conflicts 2025-10-05 16:29:00 +08:00
Afiq Hamzah 95ae90b96e Resolve merge conflicts 2025-10-05 16:23:17 +08:00
Afiq Hamzah 6d80afed8f Continue dev on pampasan module 2025-10-05 16:16:22 +08:00
aiman 0a290029a5 Tukar step pampasan v3 ke v2: 2025-10-05 16:14:54 +08:00
Ain Izazi 13a15c354f function barangkes di adminv2 2025-10-05 16:13:06 +08:00
Hafifie PKB 9c5b041497 fix specific norujukan 2025-10-05 16:11:05 +08:00
Nur Izzati 83228e8b2e tambah t_lelong dlm gadai 2025-10-05 16:11:05 +08:00
hafifierahman e320ac8219 added customer info lelong for arrahnpay 2025-10-05 16:11:05 +08:00
hafifierahman 642d9f01bb fix backdate stock audit that exceed 12 months 2025-10-05 16:11:05 +08:00
Ain Izazi Aziz 95555cd195 Merged in adminfeatbarangkesv2 (pull request #358)
function barangkes di adminv2
2025-10-05 03:45:34 +00:00
Ain Izazi 233b95b2d9 function barangkes di adminv2 2025-10-05 11:43:15 +08:00
Muhd hafifie 4200b6c305 Merged in feature/customerlelong-v2 (pull request #356)
fix specific norujukan
2025-10-05 02:00:21 +00:00
Hafifie PKB b76f804d44 fix specific norujukan 2025-10-05 09:59:37 +08:00
izzati zulkifli c76fdfaf7f Merged in izzati-hotfix-tlelong-dlm-gadai (pull request #354)
tambah t_lelong dlm gadai
2025-10-05 01:53:49 +00:00
Nur Izzati b375073520 tambah t_lelong dlm gadai 2025-10-05 09:18:47 +08:00
Muhd hafifie d878b23217 Merged in feature/customerlelong-v2 (pull request #352)
added customer info lelong for arrahnpay
2025-10-04 14:49:43 +00:00
hafifierahman 908e617431 added customer info lelong for arrahnpay 2025-10-04 22:48:45 +08:00
Muhd hafifie 66a92c2566 Merged in bugfix/stokaudit-backdate (pull request #350)
fix backdate stock audit that exceed 12 months
2025-10-01 13:47:51 +00:00
hafifierahman 177b253817 fix backdate stock audit that exceed 12 months 2025-10-01 21:35:44 +08:00
Afiq Hamzah a858d6d59d Add conditional peloperasi field for pampasan withdrawal approvals
- Implement dynamic field assignment for Kelulusan Pengeluaran Pampasan status
- Add peloperasi field only when status matches and request parameter exists
- Improve data structure handling in approval creation workflow
- Enhance conditional logic for pampasan-specific approval requirements
2025-10-01 20:07:28 +08:00
Afiq Hamzah 0a9140c85d Enhance audit trail system for approval workflows
- Add conditional audit data enrichment for specific approval actions
- Implement namapelulus and norujukan tracking for pampasan approvals
- Improve audit data structure handling for scalar and array values
- Add user field validation with fallback defaults for audit records
- Optimize approval controller with better request parameter handling
2025-09-25 10:58:58 +08:00
Nur Izzati 632c2b5190 tambah baik laporan SA by sag 2025-09-23 11:23:53 +08:00
Ain Izazi 3b44cec5a2 add di function customer nota arcc 2025-09-23 11:23:53 +08:00
Afiq Hamzah f5874b956d Update pampasan module with enhanced agreement tracking and semporna processing
- Add agreement_printed_at timestamp to pampasan table for tracking printed agreements
- Update jenis handling for semporna v2 processing logic
- Refactor barangkes controller eager loading for improved performance
- Remove obsolete jenis migration files and consolidate schema changes
- Update related models and controllers for semporna v2 compatibility
2025-09-22 13:00:08 +08:00
Afiq Hamzah 38dd97c4f2 Register pampasan to panjar after tuntutan made by pelanggan 2025-09-17 14:14:06 +08:00
Afiq Hamzah 59aeeb57f9 Continue dev on pampasan module 2025-09-17 12:39:10 +08:00
aiman 977fab853d Tukar step pampasan v3 ke v2: 2025-09-15 13:55:30 +08:00
aiman 1f27d90698 Tukar step pampasan v3 ke v2: 2025-09-14 16:03:49 +08:00
125 changed files with 10431 additions and 953 deletions
+16
View File
@@ -0,0 +1,16 @@
.git
.gitea
node_modules
vendor
.env
.env.*
!.env.example
storage/logs
storage/framework/cache
storage/framework/sessions
storage/framework/views
storage/debugbar
npm-debug.log
Dockerfile
docker-compose.yml
docker-compose.staging.yml
+28
View File
@@ -0,0 +1,28 @@
APP_NAME=Lumen
APP_ENV=production
APP_KEY=WbPGkYNmXZ6ZQplGlvl0iZ7zyW1b09xa
APP_DEBUG=true
APP_URL=https://apiannurv2.erahn.com.my
APP_TIMEZONE=Asia/Kuala_Lumpur
LOG_CHANNEL=stack
LOG_SLACK_WEBHOOK_URL=
DB_CONNECTION_2=mysql
DB_HOST_2=192.168.1.216
DB_PORT_2=3306
DB_DATABASE_2=annur_tampoi
DB_USERNAME_2=spider
DB_PASSWORD_2=arrahn@123
DB_CONNECTION_7=mysql
DB_HOST_7=192.168.1.216
DB_PORT_7=3306
DB_DATABASE_7=master_annur
DB_USERNAME_7=spider
DB_PASSWORD_7=arrahn@123
CACHE_DRIVER=file
QUEUE_CONNECTION=sync
TENNANT_MASTER_DB=master_annur
+71
View File
@@ -0,0 +1,71 @@
APP_NAME=Lumen
APP_ENV=local
APP_KEY=WbPGkYNmXZ6ZQplGlvl0iZ7zyW1b09xa
APP_DEBUG=true
APP_URL=http://localhost
APP_TIMEZONE=Asia/Kuala_Lumpur
API_ARRAHNBID=http://lelong.test/api/
API_ARRAHNBID_ANNUR=http://lelong-annur.test/api/
LOG_CHANNEL=stack
LOG_LEVEL=debug
LOG_SLACK_WEBHOOK_URL=
DB_CONNECTION=mysql
DB_HOST=mysql
DB_PORT=3306
DB_DATABASE=erahn_xtra
DB_USERNAME=root
DB_PASSWORD=root
DB_CONNECTION_7=mysql
DB_HOST_7=mysql
DB_PORT_7=3306
DB_DATABASE_7=master_erahn
DB_USERNAME_7=root
DB_PASSWORD_7=root
# DB_CONNECTION_3=mysql
# DB_HOST_3=127.0.0.1
# DB_PORT_3=3306
# DB_DATABASE_3=erahn_baling
# DB_USERNAME_3=root
# DB_PASSWORD_3=root
# DB_CONNECTION_4=mysql
# DB_HOST_4=127.0.0.1
# DB_PORT_4=3306
# DB_DATABASE_4=arrahn_ld
# DB_USERNAME_4=root
# DB_PASSWORD_4=root
# DB_CONNECTION_5=mysql
# DB_HOST_5=127.0.0.1
# DB_PORT_5=3306
# DB_DATABASE_5=erahn_segamat
# DB_USERNAME_5=root
# DB_PASSWORD_5=root
# DB_CONNECTION_6=mysql
# DB_HOST_6=127.0.0.1
# DB_PORT_6=3306
# DB_DATABASE_6=arrahn_kb2
# DB_USERNAME_6=spider
# DB_PASSWORD_6=G0dz!ll42020
# DB_CONNECTION_8=mysql
# DB_HOST_8=127.0.0.1
# DB_PORT_8=3306
# DB_DATABASE_8=arrahn_klanas
# DB_USERNAME_8=spider
# DB_PASSWORD_8=G0dz!ll42020
TENNANT_MASTER_DB=master_erahn
TENNANT_KAUNTER_DB=kaunter_erahn
KAUNTER_URL=http://host.docker.internal:8081
INTERNAL_NOTIFICATION_SECRET=erahn-local-notification-secret
CACHE_DRIVER=file
QUEUE_CONNECTION=sync
+16 -163
View File
@@ -5,6 +5,7 @@ APP_DEBUG=true
APP_URL=http://api_arrahn.test APP_URL=http://api_arrahn.test
APP_TIMEZONE=Asia/Kuala_Lumpur APP_TIMEZONE=Asia/Kuala_Lumpur
API_ARRAHNBID=http://lelong.test/api/ API_ARRAHNBID=http://lelong.test/api/
API_ARRAHNBID_ANNUR=http://lelong-annur.test/api/
LOG_CHANNEL=stack LOG_CHANNEL=stack
LOG_SLACK_WEBHOOK_URL= LOG_SLACK_WEBHOOK_URL=
@@ -86,172 +87,24 @@ DB_DATABASE_11=arrahn_pputeh
DB_USERNAME_11=spider DB_USERNAME_11=spider
DB_PASSWORD_11=G0dz!ll42020 DB_PASSWORD_11=G0dz!ll42020
DB_CONNECTION_12=mysql
DB_HOST_12=127.0.0.1
DB_PORT_12=3306
DB_DATABASE_12=arrahn_rpanjang
DB_USERNAME_12=spider
DB_PASSWORD_12=G0dz!ll42020
DB_CONNECTION_13=mysql
DB_HOST_13=127.0.0.1
DB_PORT_13=3306
DB_DATABASE_13=arrahn_tmerah
DB_USERNAME_13=spider
DB_PASSWORD_13=G0dz!ll42020
DB_CONNECTION_14=mysql
DB_HOST_14=127.0.0.1
DB_PORT_14=3306
DB_DATABASE_14=arrahn_wb
DB_USERNAME_14=spider
DB_PASSWORD_14=G0dz!ll42020
DB_CONNECTION_15=mysql
DB_HOST_15=127.0.0.1
DB_PORT_15=3306
DB_DATABASE_15=arrahn_wcy
DB_USERNAME_15=spider
DB_PASSWORD_15=G0dz!ll42020
DB_CONNECTION_16=mysql
DB_HOST_16=127.0.0.1
DB_PORT_16=3306
DB_DATABASE_16=arrahn_bentong
DB_USERNAME_16=spider
DB_PASSWORD_16=G0dz!ll42020
DB_CONNECTION_17=mysql
DB_HOST_17=192.168.0.102
DB_PORT_17=3306
DB_DATABASE_17=arrahn_kajang
DB_USERNAME_17=spider
DB_PASSWORD_17=G0dz!ll42020
DB_CONNECTION_18=mysql
DB_HOST_18=192.168.0.102
DB_PORT_18=3306
DB_DATABASE_18=arrahn_kangar
DB_USERNAME_18=spider
DB_PASSWORD_18=G0dz!ll42020
DB_CONNECTION_19=mysql
DB_HOST_19=192.168.0.102
DB_PORT_19=3306
DB_DATABASE_19=arrahn_kuantan
DB_USERNAME_19=spider
DB_PASSWORD_19=G0dz!ll42020
DB_CONNECTION_20=mysql
DB_HOST_20=192.168.0.102
DB_PORT_20=3306
DB_DATABASE_20=arrahn_pgudang
DB_USERNAME_20=spider
DB_PASSWORD_20=G0dz!ll42020
DB_CONNECTION_21=mysql
DB_HOST_21=192.168.0.102
DB_PORT_21=3306
DB_DATABASE_21=arrahn_raub
DB_USERNAME_21=spider
DB_PASSWORD_21=G0dz!ll42020
DB_CONNECTION_22=mysql
DB_HOST_22=192.168.0.102
DB_PORT_22=3306
DB_DATABASE_22=arrahn_rlaut
DB_USERNAME_22=spider
DB_PASSWORD_22=G0dz!ll42020
DB_CONNECTION_23=mysql
DB_HOST_23=192.168.0.102
DB_PORT_23=3306
DB_DATABASE_23=arrahn_skudai
DB_USERNAME_23=spider
DB_PASSWORD_23=G0dz!ll42020
DB_CONNECTION_24=mysql
DB_HOST_24=192.168.0.102
DB_PORT_24=3306
DB_DATABASE_24=arrahn_spetani
DB_USERNAME_24=spider
DB_PASSWORD_24=G0dz!ll42020
DB_CONNECTION_25=mysql
DB_HOST_25=192.168.0.102
DB_PORT_25=3306
DB_DATABASE_25=arrahn_temerloh
DB_USERNAME_25=spider
DB_PASSWORD_25=G0dz!ll42020
DB_CONNECTION_26=mysql
DB_HOST_26=192.168.0.103
DB_PORT_26=3306
DB_DATABASE_26=arrahn_api2
DB_USERNAME_26=spider
DB_PASSWORD_26=G0dz!ll42020
DB_CONNECTION_27=mysql
DB_HOST_27=192.168.0.103
DB_PORT_27=3306
DB_DATABASE_27=arrahn_beaufort
DB_USERNAME_27=spider
DB_PASSWORD_27=G0dz!ll42020
DB_CONNECTION_28=mysql
DB_HOST_28=192.168.0.103
DB_PORT_28=3306
DB_DATABASE_28=arrahn_kbelud
DB_USERNAME_28=spider
DB_PASSWORD_28=G0dz!ll42020
DB_CONNECTION_29=mysql
DB_HOST_29=192.168.0.103
DB_PORT_29=3306
DB_DATABASE_29=arrahn_keningau
DB_USERNAME_29=spider
DB_PASSWORD_29=G0dz!ll42020
DB_CONNECTION_30=mysql
DB_HOST_30=192.168.0.103
DB_PORT_30=3306
DB_DATABASE_30=arrahn_putatan
DB_USERNAME_30=spider
DB_PASSWORD_30=G0dz!ll42020
DB_CONNECTION_31=mysql
DB_HOST_31=192.168.0.103
DB_PORT_31=3306
DB_DATABASE_31=arrahn_sandakan
DB_USERNAME_31=spider
DB_PASSWORD_31=G0dz!ll42020
DB_CONNECTION_32=mysql
DB_HOST_32=192.168.0.103
DB_PORT_32=3306
DB_DATABASE_32=arrahn_tawau
DB_USERNAME_32=spider
DB_PASSWORD_32=G0dz!ll42020
DB_CONNECTION_33=mysql
DB_HOST_33=192.168.0.103
DB_PORT_33=3306
DB_DATABASE_33=arrahn_tuaran
DB_USERNAME_33=spider
DB_PASSWORD_33=G0dz!ll42020
CACHE_DRIVER=file CACHE_DRIVER=file
QUEUE_CONNECTION=sync QUEUE_CONNECTION=sync
WABOT_API=https://md.wabot.my/api/send.php MAX_MUTUEMAS=true
WABOT_INSTANCES_ID=63F40BD120DB4
# WABOT_INSTANCES_ID=64892FD7440A6
WABOT_TOKEN_KEYS=cbee7e95cf3ffbfa0531d5fddfd44f87
TENNANT_MASTER_DB=master_erahn
TENNANT_KAUNTER_DB=kaunter_erahn
ONEWAYSMS_API=http://gateway.onewaysms.com.my:10001/api.aspx KAUNTER_URL=http://host.docker.internal:8081
ONEWAYSMS_AUTH_USER=APIUK330HDAFO INTERNAL_NOTIFICATION_SECRET=
ONEWAYSMS_AUTH_PASS=APIUK330HDAFOUK330
ADMIN_PHONE_NUMBER=60178916936 LOGVIEWER_PASSWORD=
ACTIVE_JOB_SERVER=false
WHATSAPP_TOKEN= # Paste token from Graph API explorer.
WHATSAPP_PHONE_NUMBER_ID=1323449077519027
WHATSAPP_API_VERSION=v25.0
WHATSAPP_TEMPLATE=hello_world
WHATSAPP_TEMPLATE_LANG=en_US
WHATSAPP_VERIFY_TOKEN= # webhook verify token
WHATSAPP_APP_SECRET= # X-Hub-Signature-256 checks; need to be enable first
ADMIN_PHONE_NUMBER=60193450165
+89
View File
@@ -0,0 +1,89 @@
APP_NAME=Lumen
APP_ENV=production
APP_KEY=WbPGkYNmXZ6ZQplGlvl0iZ7zyW1b09xa
APP_DEBUG=false
APP_URL=https://apiujrah.erahn.com.my
APP_TIMEZONE=Asia/Kuala_Lumpur
API_ARRAHNBID=https://adminbid-kopkb.erahn.com.my/api/
API_ARRAHNBID_ANNUR=https://adminbid-annur.erahn.com.my/api/
LOG_CHANNEL=stack
LOG_SLACK_WEBHOOK_URL=
LOGVIEWER_PASSWORD="$2y$10$k7eiUyZdm3BruwAaT1gbmelTm.PPgZptOEQT1nlBjyiR84a4KBMlm"
DB_CONNECTION_2=mysql
DB_HOST_2=192.168.1.216
DB_PORT_2=3306
DB_DATABASE_2=erahn_xtra
DB_USERNAME_2=spider
DB_PASSWORD_2=arrahn@123
DB_CONNECTION_3=mysql
DB_HOST_3=192.168.1.216
DB_PORT_3=3306
DB_DATABASE_3=erahn_baling
DB_USERNAME_3=spider
DB_PASSWORD_3=arrahn@123
DB_CONNECTION_4=mysql
DB_HOST_4=192.168.1.216
DB_PORT_4=3306
DB_DATABASE_4=arrahn_ld
DB_USERNAME_4=spider
DB_PASSWORD_4=arrahn@123
DB_CONNECTION_5=mysql
DB_HOST_5=192.168.1.216
DB_PORT_5=3306
DB_DATABASE_5=erahn_segamat
DB_USERNAME_5=spider
DB_PASSWORD_5=arrahn@123
DB_CONNECTION_6=mysql
DB_HOST_6=192.168.1.216
DB_PORT_6=3306
DB_DATABASE_6=erahn_terengganu
DB_USERNAME_6=spider
DB_PASSWORD_6=arrahn@123
DB_CONNECTION_8=mysql
DB_HOST_8=192.168.1.216
DB_PORT_8=3306
DB_DATABASE_8=erahn_benoni
DB_USERNAME_8=spider
DB_PASSWORD_8=arrahn@123
DB_CONNECTION_7=mysql
DB_HOST_7=192.168.1.216
DB_PORT_7=3306
DB_DATABASE_7=master_erahn
DB_USERNAME_7=spider
DB_PASSWORD_7=arrahn@123
DB_CONNECTION_9=mysql
DB_HOST_9=192.168.1.216
DB_PORT_9=3306
DB_DATABASE_9=annur_tampoi
DB_USERNAME_9=spider
DB_PASSWORD_9=arrahn@123
CACHE_DRIVER=file
QUEUE_CONNECTION=sync
MAX_MUTUEMAS=true
TENNANT_MASTER_DB=master_erahn
TENNANT_KAUNTER_DB=kaunter_erahn
KAUNTER_URL=https://ujrah.erahn.com.my
INTERNAL_NOTIFICATION_SECRET="nIDTe(u@6[)VLJyd"
WHATSAPP_CLOUD_ENABLED=true
WHATSAPP_TOKEN=EAAZAonT56AO0BSnZAhWLi4UXDRT6iAldbiybxSQZAnGrzIke1QiNWvQkZAbQQTjWeVZC5bL1gEBhW6ff3Shf79nowXiTQEwyxqgZAZB6ZATwFCeTs8MZA5H6ZA76IJBuVqRiAZBvZCfkeSurbUNpEWyi9W7zsT2GWiZCLX8meX0KCfDHu7cp4aBgVu1Ps5ZCRO3bP4ZCQZDZD
WHATSAPP_PHONE_NUMBER_ID=1375899418935337
WHATSAPP_API_VERSION=v25.0
WHATSAPP_TEMPLATE=hebahan_pembiayaan_online
WHATSAPP_TEMPLATE_LANG=ms
WHATSAPP_VERIFY_TOKEN=418ed86d49422071681c76bed25ae1cb7e90456c794a92f1c9ea417945a35a0a
WHATSAPP_APP_SECRET=
ADMIN_PHONE_NUMBER=
+100
View File
@@ -0,0 +1,100 @@
APP_NAME=Lumen
APP_ENV=staging
APP_KEY=WbPGkYNmXZ6ZQplGlvl0iZ7zyW1b09xa
APP_DEBUG=true
APP_URL=http://127.0.0.1:8090
APP_TIMEZONE=Asia/Kuala_Lumpur
API_ARRAHNBID=http://lelong.test/api/
API_ARRAHNBID_ANNUR=http://lelong-annur.test/api/
HTTP_PORT=8090
MYSQL_PUBLISH_PORT=3308
LOG_CHANNEL=stack
LOG_LEVEL=debug
LOG_SLACK_WEBHOOK_URL=
LOGVIEWER_PASSWORD=
DB_CONNECTION=mysql
DB_HOST=mysql
DB_PORT=3306
DB_DATABASE=erahn_xtra
DB_USERNAME=root
DB_PASSWORD=root
DB_CONNECTION_7=mysql
DB_HOST_7=mysql
DB_PORT_7=3306
DB_DATABASE_7=master_erahn
DB_USERNAME_7=root
DB_PASSWORD_7=root
DB_CONNECTION_2=mysql
DB_HOST_2=mysql
DB_PORT_2=3306
DB_DATABASE_2=erahn_xtra
DB_USERNAME_2=root
DB_PASSWORD_2=root
DB_CONNECTION_3=mysql
DB_HOST_3=mysql
DB_PORT_3=3306
DB_DATABASE_3=erahn_baling
DB_USERNAME_3=root
DB_PASSWORD_3=root
DB_CONNECTION_4=mysql
DB_HOST_4=mysql
DB_PORT_4=3306
DB_DATABASE_4=arrahn_ld
DB_USERNAME_4=root
DB_PASSWORD_4=root
DB_CONNECTION_5=mysql
DB_HOST_5=mysql
DB_PORT_5=3306
DB_DATABASE_5=erahn_segamat
DB_USERNAME_5=root
DB_PASSWORD_5=root
DB_CONNECTION_7=mysql
DB_HOST_7=mysql
DB_PORT_7=3306
DB_DATABASE_7=master_erahn
DB_USERNAME_7=root
DB_PASSWORD_7=root
DB_CONNECTION_6=mysql
DB_HOST_6=mysql
DB_PORT_6=3306
DB_DATABASE_6=erahn_test
DB_USERNAME_6=root
DB_PASSWORD_6=root
DB_CONNECTION_9=mysql
DB_HOST_9=mysql
DB_PORT_9=3306
DB_DATABASE_9=annur_tampoi
DB_USERNAME_9=root
DB_PASSWORD_9=root
CACHE_DRIVER=file
QUEUE_CONNECTION=sync
MAX_MUTUEMAS=true
TENNANT_MASTER_DB=master_erahn
TENNANT_KAUNTER_DB=kaunter_erahn
KAUNTER_URL=https://staging.erahn.com.my/login
INTERNAL_NOTIFICATION_SECRET=staging_noti_secret
WHATSAPP_CLOUD_ENABLED=false
WHATSAPP_TOKEN=EAAZAonT56AO0BSnZAhWLi4UXDRT6iAldbiybxSQZAnGrzIke1QiNWvQkZAbQQTjWeVZC5bL1gEBhW6ff3Shf79nowXiTQEwyxqgZAZB6ZATwFCeTs8MZA5H6ZA76IJBuVqRiAZBvZCfkeSurbUNpEWyi9W7zsT2GWiZCLX8meX0KCfDHu7cp4aBgVu1Ps5ZCRO3bP4ZCQZDZD
WHATSAPP_PHONE_NUMBER_ID=1375899418935337
WHATSAPP_API_VERSION=v25.0
WHATSAPP_TEMPLATE=hebahan_pembiayaan_online
WHATSAPP_TEMPLATE_LANG=ms
WHATSAPP_VERIFY_TOKEN=418ed86d49422071681c76bed25ae1cb7e90456c794a92f1c9ea417945a35a0a
WHATSAPP_APP_SECRET=
ADMIN_PHONE_NUMBER=
-244
View File
@@ -1,244 +0,0 @@
APP_NAME=Lumen
APP_ENV=local
APP_KEY=WbPGkYNmXZ6ZQplGlvl0iZ7zyW1b09xa
APP_DEBUG=false
APP_URL=https://api.arrahn.com.my
APP_TIMEZONE=Asia/Kuala_Lumpur
LOG_CHANNEL=stack
LOG_SLACK_WEBHOOK_URL=
DB_CONNECTION=mysql
DB_HOST=172.16.4.102
DB_PORT=3306
DB_DATABASE=arrahn_kb2
DB_USERNAME=zone2
DB_PASSWORD=G0dz!ll4@2020
DB_CONNECTION_2=mysql
DB_HOST_2=172.16.4.102
DB_PORT_2=3306
DB_DATABASE_2=arrahn_wcy
DB_USERNAME_2=zone2
DB_PASSWORD_2=G0dz!ll4@2020
DB_CONNECTION_3=mysql
DB_HOST_3=172.16.4.102
DB_PORT_3=3306
DB_DATABASE_3=arrahn_1stop
DB_USERNAME_3=zone2
DB_PASSWORD_3=G0dz!ll4@2020
DB_CONNECTION_4=mysql
DB_HOST_4=172.16.4.102
DB_PORT_4=3306
DB_DATABASE_4=arrahn_jlwt
DB_USERNAME_4=zone2
DB_PASSWORD_4=G0dz!ll4@2020
DB_CONNECTION_5=mysql
DB_HOST_5=172.16.4.102
DB_PORT_5=3306
DB_DATABASE_5=arrahn_wb
DB_USERNAME_5=zone2
DB_PASSWORD_5=G0dz!ll4@2020
DB_CONNECTION_6=mysql
DB_HOST_6=172.16.4.102
DB_PORT_6=3306
DB_DATABASE_6=arrahn_kls
DB_USERNAME_6=zone2
DB_PASSWORD_6=G0dz!ll4@2020
DB_CONNECTION_7=mysql
DB_HOST_7=172.16.4.102
DB_PORT_7=3306
DB_DATABASE_7=online_arrahn
DB_USERNAME_7=zone2
DB_PASSWORD_7=G0dz!ll4@2020
DB_CONNECTION_8=mysql
DB_HOST_8=172.16.4.102
DB_PORT_8=3306
DB_DATABASE_8=arrahn_pp
DB_USERNAME_8=zone2
DB_PASSWORD_8=G0dz!ll4@2020
DB_CONNECTION_9=mysql
DB_HOST_9=172.16.4.102
DB_PORT_9=3306
DB_DATABASE_9=arrahn_mace
DB_USERNAME_9=zone2
DB_PASSWORD_9=G0dz!ll4@2020
DB_CONNECTION_10=mysql
DB_HOST_10=172.16.4.102
DB_PORT_10=3306
DB_DATABASE_10=arrahn_pm
DB_USERNAME_10=zone2
DB_PASSWORD_10=G0dz!ll4@2020
DB_CONNECTION_11=mysql
DB_HOST_11=172.16.4.102
DB_PORT_11=3306
DB_DATABASE_11=arrahn_gm
DB_USERNAME_11=zone2
DB_PASSWORD_11=G0dz!ll4@2020
DB_CONNECTION_12=mysql
DB_HOST_12172.16.4.102
DB_PORT_12=3306
DB_DATABASE_12=arrahn_gcl
DB_USERNAME_12=zone2
DB_PASSWORD_12=G0dz!ll4@2020
DB_CONNECTION_13=mysql
DB_HOST_13=172.16.4.102
DB_PORT_13=3306
DB_DATABASE_13=arrahn_jli
DB_USERNAME_13=zone2
DB_PASSWORD_13=G0dz!ll4@2020
DB_CONNECTION_14=mysql
DB_HOST_14=172.16.4.102
DB_PORT_14=3306
DB_DATABASE_14=arrahn_rp
DB_USERNAME_14=zone2
DB_PASSWORD_14=G0dz!ll4@2020
DB_CONNECTION_15=mysql
DB_HOST_15=172.16.4.102
DB_PORT_15=3306
DB_DATABASE_15=arrahn_ktn
DB_USERNAME_15=zone2
DB_PASSWORD_15=G0dz!ll4@2020
DB_CONNECTION_16=mysql
DB_HOST_16=172.16.4.102
DB_PORT_16=3306
DB_DATABASE_16=arrahn_pg
DB_USERNAME_16=zone2
DB_PASSWORD_16=G0dz!ll4@2020
DB_CONNECTION_17=mysql
DB_HOST_17=172.16.4.102
DB_PORT_17=3306
DB_DATABASE_17=arrahn_skudai
DB_USERNAME_17=zone2
DB_PASSWORD_17=G0dz!ll4@2020
DB_CONNECTION_18=mysql
DB_HOST_18=172.16.4.102
DB_PORT_18=3306
DB_DATABASE_18=arrahn_pttn
DB_USERNAME_18=zone2
DB_PASSWORD_18=G0dz!ll4@2020
DB_CONNECTION_19=mysql
DB_HOST_19=172.16.4.102
DB_PORT_19=3306
DB_DATABASE_19=arrahn_btg
DB_USERNAME_19=zone2
DB_PASSWORD_19=G0dz!ll4@2020
DB_CONNECTION_20=mysql
DB_HOST_20=172.16.4.102
DB_PORT_20=3306
DB_DATABASE_20=arrahn_raub
DB_USERNAME_20=zone2
DB_PASSWORD_20=G0dz!ll4@2020
DB_CONNECTION_21=mysql
DB_HOST_21=172.16.4.102
DB_PORT_21=3306
DB_DATABASE_21=arrahn_kgr
DB_USERNAME_21=zone2
DB_PASSWORD_21=G0dz!ll4@2020
DB_CONNECTION_22=mysql
DB_HOST_22=172.16.4.102
DB_PORT_22=3306
DB_DATABASE_22=arrahn_sdk
DB_USERNAME_22=zone2
DB_PASSWORD_22=G0dz!ll4@2020
DB_CONNECTION_23=mysql
DB_HOST_23=172.16.4.102
DB_PORT_23=3306
DB_DATABASE_23=arrahn_sp
DB_USERNAME_23=zone2
DB_PASSWORD_23=G0dz!ll4@2020
DB_CONNECTION_24=mysql
DB_HOST_24=172.16.4.102
DB_PORT_24=3306
DB_DATABASE_24=arrahn_twu
DB_USERNAME_24=zone2
DB_PASSWORD_24=G0dz!ll4@2020
DB_CONNECTION_25=mysql
DB_HOST_25=172.16.4.102
DB_PORT_25=3306
DB_DATABASE_25=arrahn_api2
DB_USERNAME_25=zone2
DB_PASSWORD_25=G0dz!ll4@2020
DB_CONNECTION_26=mysql
DB_HOST_26=172.16.4.102
DB_PORT_26=3306
DB_DATABASE_26=arrahn_kjg
DB_USERNAME_26=zone2
DB_PASSWORD_26=G0dz!ll4@2020
DB_CONNECTION_27=mysql
DB_HOST_27=172.16.4.102
DB_PORT_27=3306
DB_DATABASE_27=arrahn_rl
DB_USERNAME_27=zone2
DB_PASSWORD_27=G0dz!ll4@2020
DB_CONNECTION_28=mysql
DB_HOST_28=172.16.4.102
DB_PORT_28=3306
DB_DATABASE_28=arrahn_bfort
DB_USERNAME_28=zone2
DB_PASSWORD_28=G0dz!ll4@2020
DB_CONNECTION_29=mysql
DB_HOST_29=172.16.4.102
DB_PORT_29=3306
DB_DATABASE_29=arrahn_kbelud
DB_USERNAME_29=zone2
DB_PASSWORD_29=G0dz!ll4@2020
DB_CONNECTION_30=mysql
DB_HOST_30=172.16.4.102
DB_PORT_30=3306
DB_DATABASE_30=arrahn_tuaran
DB_USERNAME_30=zone2
DB_PASSWORD_30=G0dz!ll4@2020
DB_CONNECTION_31=mysql
DB_HOST_31=172.16.4.102
DB_PORT_31=3306
DB_DATABASE_31=arrahn_kngau
DB_USERNAME_31=zone2
DB_PASSWORD_31=G0dz!ll4@2020
DB_CONNECTION_32=mysql
DB_HOST_32=172.16.4.102
DB_PORT_32=3306
DB_DATABASE_32=arrahn_tm
DB_USERNAME_32=zone2
DB_PASSWORD_32=G0dz!ll4@2020
DB_CONNECTION_33=mysql
DB_HOST_33=172.16.4.102
DB_PORT_33=3306
DB_DATABASE_33=arrahn_tmlh
DB_USERNAME_33=zone2
DB_PASSWORD_33=G0dz!ll4@2020
CACHE_DRIVER=file
QUEUE_CONNECTION=sync
+49
View File
@@ -0,0 +1,49 @@
name: Build Docker Image
on:
push:
branches:
- staging
tags:
- "v*"
workflow_dispatch:
jobs:
build-backend:
runs-on: docker
steps:
- name: Checkout repository
uses: actions/checkout@v4
- name: Login to Docker registry
run: |
echo "${{ secrets.REGISTRY_PASSWORD }}" | \
docker login git.koppkb.com \
-u "${{ secrets.REGISTRY_USERNAME }}" \
--password-stdin
- name: Build & push backend image
run: |
set -e
IMAGE="git.koppkb.com/kopkb/api_arrahn"
TAGS="-t ${IMAGE}:${{ gitea.sha }}"
if [ "${{ gitea.ref_type }}" = "tag" ] && echo "${{ gitea.ref_name }}" | grep -q '^v'; then
TAGS="${TAGS} -t ${IMAGE}:${{ gitea.ref_name }}"
fi
if [ "${{ gitea.ref_name }}" = "staging" ]; then
TAGS="${TAGS} -t ${IMAGE}:staging"
fi
echo "Building and pushing backend: ${TAGS}"
docker buildx build \
--target staging \
--platform linux/amd64 \
--cache-from type=registry,ref=${IMAGE}:buildcache,ignore-error=true \
--cache-to type=registry,ref=${IMAGE}:buildcache,mode=max \
-f docker/php/Dockerfile \
${TAGS} \
--push .
+122
View File
@@ -0,0 +1,122 @@
name: Deploy to Staging
on:
workflow_dispatch:
inputs:
image_tag:
description: "Docker image tag to deploy (commit SHA, staging, or v*)"
required: true
default: "staging"
type: string
env:
APP_IMAGE: git.koppkb.com/kopkb/api_arrahn
DEPLOY_DIR: /home/arrahn/Project/api_arrahn
jobs:
deploy:
runs-on: host
steps:
- name: Checkout repository
uses: actions/checkout@v4
with:
ref: ${{ inputs.image_tag }}
- name: Login to Docker registry
run: |
echo "${{ secrets.REGISTRY_PASSWORD }}" | \
docker login git.koppkb.com \
-u "${{ secrets.REGISTRY_USERNAME }}" \
--password-stdin
- name: Verify image exists in registry
run: |
set -e
IMAGE_TAG="${{ inputs.image_tag }}"
IMAGE="${APP_IMAGE}:${IMAGE_TAG}"
echo "Checking if image exists: ${IMAGE}"
if ! docker manifest inspect "${IMAGE}" > /dev/null 2>&1; then
echo "ERROR: Image ${IMAGE} does not exist in registry!"
echo "Run the Build Docker Image workflow first."
exit 1
fi
echo "✓ ${IMAGE} found"
- name: Pull Docker image
run: |
set -e
IMAGE_TAG="${{ inputs.image_tag }}"
docker pull "${APP_IMAGE}:${IMAGE_TAG}"
echo "✓ Image pulled successfully"
- name: Sync compose file and deploy
run: |
set -e
IMAGE_TAG="${{ inputs.image_tag }}"
mkdir -p "${DEPLOY_DIR}/docker/nginx" "${DEPLOY_DIR}/docker/mysql"
cp docker-compose.staging.yml "${DEPLOY_DIR}/docker-compose.yml"
cp docker/nginx/default.conf "${DEPLOY_DIR}/docker/nginx/default.conf"
cp -R docker/mysql/init "${DEPLOY_DIR}/docker/mysql/"
if [ ! -f "${DEPLOY_DIR}/.env.staging" ]; then
if [ -f .env.staging ]; then
cp .env.staging "${DEPLOY_DIR}/.env.staging"
echo "Copied .env.staging from repo (first deploy). Edit ${DEPLOY_DIR}/.env.staging on the server if needed."
else
echo "ERROR: ${DEPLOY_DIR}/.env.staging is missing on the server"
exit 1
fi
fi
cd "${DEPLOY_DIR}"
export APP_IMAGE
export IMAGE_TAG
docker compose --env-file .env.staging -f docker-compose.yml pull app
docker compose --env-file .env.staging -f docker-compose.yml up -d --no-build --force-recreate --remove-orphans app web
echo "✓ Deployed IMAGE_TAG=${IMAGE_TAG}"
- name: Verify deployment
run: |
set -e
cd "${DEPLOY_DIR}"
echo "Waiting for services to start..."
sleep 10
for SERVICE in app web mysql; do
STATUS=$(docker compose --env-file .env.staging -f docker-compose.yml ps --status running --format '{{.Name}}' "$SERVICE" 2>/dev/null || true)
if [ -z "$STATUS" ]; then
echo "ERROR: ${SERVICE} is not running"
docker compose --env-file .env.staging -f docker-compose.yml ps
docker compose --env-file .env.staging -f docker-compose.yml logs --tail=50 "$SERVICE" || true
exit 1
fi
echo "✓ ${SERVICE} is running (${STATUS})"
done
HTTP_PORT=$(grep -E '^HTTP_PORT=' .env.staging 2>/dev/null | cut -d= -f2- | tr -d '"' || true)
HTTP_PORT=${HTTP_PORT:-8090}
check_health() {
NAME=$1
URL=$2
for i in 1 2 3 4 5 6; do
if curl -sf "$URL" > /dev/null; then
echo "✓ ${NAME} health check passed (${URL})"
return 0
fi
echo "Waiting for ${NAME}... attempt ${i}/6"
sleep 5
done
echo "ERROR: ${NAME} health check failed (${URL})"
docker compose --env-file .env.staging -f docker-compose.yml logs --tail=50 app web || true
return 1
}
check_health "api" "http://127.0.0.1:${HTTP_PORT}/health"
+2 -1
View File
@@ -5,6 +5,7 @@ Homestead.yaml
.env .env
.phpunit.result.cache .phpunit.result.cache
ray.php ray.php
docker-compose.yml
/docker_src /docker_src
/.vscode /.vscode
**/.DS_Store
db-dump
+29
View File
@@ -1 +1,30 @@
You know what is this when you in this project You know what is this when you in this project
If you does't know what is this you probably in wrong project
```sql
--- for all ip
CREATE USER 'master_erahn'@'%' IDENTIFIED BY 'password';
--- for specific ip
CREATE USER 'kaunter_erahn'@'localhost' IDENTIFIED BY 'password';
GRANT ALL PRIVILEGES ON kaunter_erahn.* TO 'kaunter_erahn'@'%';
FLUSH PRIVILEGES;
```
Gadai=Pembiayaan
Tebus=penyelesaian penuh/ansuran
## Load db dump without using docker
```bash
docker exec -i api_arrahn_staging_mysql mysql -uroot -proot erahn_test < erahn_test.sql
```
## Disable the cawangan in arrahn_master_db using feature flag
## Feature Flag
1. Register the flag in api_arrahn/app/Feature.php
2. Block the real work in the API
3. Hide the UI in kaunter from the
4. Enable a pilot from Admin → Ciri Cawangan (or SQL):
BIN
View File
Binary file not shown.
+22
View File
@@ -0,0 +1,22 @@
<?php
namespace App;
use Illuminate\Database\Eloquent\Model;
class BatchPembiayaanOnline extends Model
{
protected $table = 'batch_pembiayaan_online';
protected $fillable = [
'batch_no',
'kodcaw',
'tarikh',
'slot',
'bilangan',
'jumlah_keseluruhan',
'status',
'pc_submitted_by',
'submitted_at',
];
}
+11
View File
@@ -11,6 +11,17 @@ class Cawangan extends Model
public $timestamps = false; public $timestamps = false;
/**
* Display name from master table (`details_caw`).
* Keep this as the single mapping so callers do not guess nama/namacaw.
*/
public function getNamaCawanganAttribute()
{
$nama = trim((string) ($this->attributes['details_caw'] ?? ''));
return $nama !== '' ? $nama : (string) ($this->attributes['kodcaw'] ?? '');
}
/** /**
* The attributes that are mass assignable. * The attributes that are mass assignable.
* *
+21
View File
@@ -0,0 +1,21 @@
<?php
namespace App;
use Illuminate\Database\Eloquent\Model;
class CawanganFeature extends Model
{
protected $table = 'cawangan_feature';
protected $connection = 'mysql7';
protected $fillable = [
'kodcaw',
'feature',
'enabled',
];
protected $casts = [
'enabled' => 'integer',
];
}
@@ -80,7 +80,7 @@ class CawanganDebugConnections extends Command
return $idToNameMap[$item['mysql']] !== $item['database']; return $idToNameMap[$item['mysql']] !== $item['database'];
}); });
} catch (\Throwable $th) { } catch (\Throwable $th) {
dump(sprintf('Connection %s not found in table online_arrahn.arrahn_master_db but present in config. Make sure both of connection exist in both app/config and arrahn_master_db', $tested_connection)); dump(sprintf('Connection %s not found in table %s.arrahn_master_db but present in config. Make sure both of connection exist in both app/config and arrahn_master_db', $tested_connection, config('tennant_database.master_db')));
return; return;
} }
+56
View File
@@ -0,0 +1,56 @@
<?php
namespace App\Console\Commands;
use App\Services\Whatsapp\WhatsappCloudClient;
use Illuminate\Console\Command;
class WhatsappTestSend extends Command
{
protected $signature = 'whatsapp:test {--to= : Recipient MSISDN, default ADMIN_PHONE_NUMBER}';
protected $description = 'Send the configured WhatsApp Cloud template to a test number';
public function handle()
{
$client = new WhatsappCloudClient();
if (!$client->isConfigured()) {
$this->error('Set WHATSAPP_TOKEN and WHATSAPP_PHONE_NUMBER_ID in .env first.');
return 1;
}
$to = $client->normalizeMsisdn($this->option('to') ?: env('ADMIN_PHONE_NUMBER'));
if (!$to) {
$this->error('Pass --to=60193450165 or set ADMIN_PHONE_NUMBER.');
return 1;
}
$template = config('whatsapp.template', 'hello_world');
$lang = config('whatsapp.template_lang', 'en_US');
$bodyParams = [];
if (strtolower($template) !== 'hello_world') {
// pembiayaan_online_paid: SAG, amaun, bank, 4 digit akhir, tarikh, rujukan
$bodyParams = [
'TEST-SAG',
'100.00',
'Maybank',
'1234',
date('d/m/Y'),
'TEST-REF',
];
}
$this->info("Sending {$template} ({$lang}) to {$to} …");
$response = $client->sendTemplate($to, $template, $lang, $bodyParams);
if ($response->successful()) {
$this->info('OK ' . $response->status() . ' ' . $response->body());
return 0;
}
$this->error('FAIL ' . $response->status() . ' ' . $response->body());
return 1;
}
}
+1
View File
@@ -24,6 +24,7 @@ class Kernel extends ConsoleKernel
Commands\ClearCachesAll::class, Commands\ClearCachesAll::class,
Commands\RestartSupervisor::class, Commands\RestartSupervisor::class,
Commands\InsertSempornaData::class, Commands\InsertSempornaData::class,
Commands\WhatsappTestSend::class,
//Commands\ImportCsv::class, //Commands\ImportCsv::class,
]; ];
+2 -1
View File
@@ -62,7 +62,8 @@ class Customer extends Model
'telefon2', 'telefon2',
'nota_pekerjaan', 'nota_pekerjaan',
'tagpelanggan', 'tagpelanggan',
'tag_anggota' 'tag_anggota',
'gambar_mykad'
]; ];
/** /**
+172
View File
@@ -0,0 +1,172 @@
<?php
namespace App;
class Feature
{
const PEMBIAYAAN_ONLINE = 'pembiayaan_online';
const REBET_ANNUR = 'rebet_annur';
/**
* Known flag keys. New features: add a constant here, then INSERT rows for pilot kodcaw.
*
* @return string[]
*/
public static function keys()
{
return [
self::PEMBIAYAAN_ONLINE,
self::REBET_ANNUR,
];
}
/**
* @return array<string,int>
*/
public static function defaults()
{
$map = [];
foreach (self::keys() as $key) {
$map[$key] = 0;
}
return $map;
}
/**
* Display labels for admin UI. New features: add a label here.
*
* @return array<string,string>
*/
public static function labels()
{
return [
self::PEMBIAYAAN_ONLINE => 'Pembiayaan Online',
self::REBET_ANNUR => 'Rebet / diskaun Annur',
];
}
/**
* Lelong portal base URL for this branch. rebet_annur branches (Annur/Tampoi)
* use API_ARRAHNBID_ANNUR; everyone else uses API_ARRAHNBID.
*
* Always returned with a trailing slash so callers can append 'portalApi'.
*
* @param string $kodcaw
* @return string
*/
public static function arrahnbidUrl($kodcaw)
{
$url = config('app_parameter.api_arrahnbid');
if ($kodcaw && self::enabled($kodcaw, self::REBET_ANNUR)) {
$annur = config('app_parameter.api_arrahnbid_annur');
if ($annur) {
$url = $annur;
}
}
return rtrim((string) $url, '/') . '/';
}
/**
* Missing row is off (fail closed).
*
* @param string $kodcaw
* @param string $feature
* @return bool
*/
public static function enabled($kodcaw, $feature)
{
return CawanganFeature::on('mysql7')
->where('kodcaw', $kodcaw)
->where('feature', $feature)
->where('enabled', 1)
->exists();
}
/**
* @param string $kodcaw
* @return array<string,int>
*/
public static function mapFor($kodcaw)
{
$map = self::defaults();
$rows = CawanganFeature::on('mysql7')
->where('kodcaw', $kodcaw)
->get(['feature', 'enabled']);
foreach ($rows as $row) {
$map[$row->feature] = ((int) $row->enabled) === 1 ? 1 : 0;
}
return $map;
}
/**
* @param string[] $kodcaws
* @return array<string,array<string,int>>
*/
public static function mapForMany(array $kodcaws)
{
$defaults = self::defaults();
$result = [];
foreach ($kodcaws as $kodcaw) {
$result[$kodcaw] = $defaults;
}
if (count($kodcaws) === 0) {
return $result;
}
$rows = CawanganFeature::on('mysql7')
->whereIn('kodcaw', $kodcaws)
->get(['kodcaw', 'feature', 'enabled']);
foreach ($rows as $row) {
$result[$row->kodcaw][$row->feature] = ((int) $row->enabled) === 1 ? 1 : 0;
}
return $result;
}
/**
* @param string $kodcaw
* @param string $feature
* @param bool|int $enabled
* @return bool
*/
public static function setEnabled($kodcaw, $feature, $enabled)
{
if (!in_array($feature, self::keys(), true)) {
return false;
}
CawanganFeature::on('mysql7')->updateOrCreate(
[
'kodcaw' => $kodcaw,
'feature' => $feature,
],
[
'enabled' => $enabled ? 1 : 0,
]
);
return true;
}
/**
* @param string|null $message
* @return array{ok:bool,status:int,payload:array}
*/
public static function denied($message = null)
{
return [
'ok' => false,
'status' => 403,
'payload' => [
'message' => $message ?: 'Ciri ini tidak diaktifkan untuk cawangan ini',
],
];
}
}
+8 -1
View File
@@ -9,6 +9,10 @@ class Gadai extends Model
protected $table = 'gadai'; protected $table = 'gadai';
public $timestamps = false; public $timestamps = false;
protected $attributes = [
'cara_terima' => 'TUNAI',
];
/** /**
* The attributes that are mass assignable. * The attributes that are mass assignable.
* *
@@ -25,6 +29,7 @@ class Gadai extends Model
'nilaimarhun', 'nilaimarhun',
'berat', 'berat',
'pinjaman', 'pinjaman',
'cara_terima',
'telahbayar', 'telahbayar',
'upahtelahbyr', 'upahtelahbyr',
'cajtelahbyr', 'cajtelahbyr',
@@ -73,7 +78,9 @@ class Gadai extends Model
'tagkomuditi', 'tagkomuditi',
'tempohbayar', 'tempohbayar',
'lelong_tawarruq', 'lelong_tawarruq',
'tag_tebus' 'tag_tebus',
'kadarrebet',
'diskaun'
]; ];
/** /**
+3 -3
View File
@@ -12,7 +12,7 @@ class Helper
{ {
$online_arrahn_connection = array_filter(config('database.connections'), function ($connection) { $online_arrahn_connection = array_filter(config('database.connections'), function ($connection) {
if ($connection['database'] === 'online_arrahn') { if ($connection['database'] === config('tennant_database.master_db')) {
return $connection; return $connection;
} }
}); });
@@ -43,7 +43,7 @@ class Helper
} }
}); });
$non_cawangan_database = ['lelong', 'online_arrahn', 'kaunterpkb']; $non_cawangan_database = ['lelong', config('tennant_database.master_db'), config('tennant_database.kaunter_db')];
$all_cawangan_db = array_filter($all_active_db_keys, function ($db_key) use ($non_cawangan_database) { $all_cawangan_db = array_filter($all_active_db_keys, function ($db_key) use ($non_cawangan_database) {
$isNotCawangan = in_array(config('database.connections.' . $db_key . '.database'), $non_cawangan_database); $isNotCawangan = in_array(config('database.connections.' . $db_key . '.database'), $non_cawangan_database);
@@ -74,7 +74,7 @@ class Helper
} }
}); });
$non_cawangan_database = ['lelong', 'online_arrahn', 'kaunterpkb']; $non_cawangan_database = ['lelong', config('tennant_database.master_db'), config('tennant_database.kaunter_db')];
$all_cawangan_db = array_filter($all_inactive_db_keys, function ($db_key) use ($non_cawangan_database) { $all_cawangan_db = array_filter($all_inactive_db_keys, function ($db_key) use ($non_cawangan_database) {
$isNotCawangan = in_array(config('database.connections.' . $db_key . '.database'), $non_cawangan_database); $isNotCawangan = in_array(config('database.connections.' . $db_key . '.database'), $non_cawangan_database);
+300 -25
View File
@@ -30,6 +30,7 @@ use App\Status;
use App\LookupStatus; use App\LookupStatus;
use App\ARFiles; use App\ARFiles;
use App\WTDDraft; use App\WTDDraft;
use App\WTDSimulasi;
use App\SerahBaki; use App\SerahBaki;
use App\WTD; use App\WTD;
use App\StokAudit1; use App\StokAudit1;
@@ -62,7 +63,6 @@ use Illuminate\Pagination\LengthAwarePaginator;
use Illuminate\Http\Request; use Illuminate\Http\Request;
use Illuminate\Support\Facades\Log; use Illuminate\Support\Facades\Log;
use App\Jobs\AccountCheckJob; use App\Jobs\AccountCheckJob;
use App\Penyelarasan;
use Illuminate\Support\Str; use Illuminate\Support\Str;
use Illuminate\Support\Facades\Cache; use Illuminate\Support\Facades\Cache;
@@ -2364,19 +2364,84 @@ class AdminPageController extends Controller
$cawangan = Cawangan::on('mysql7')->where('kodcaw','=',$request->kodcaw)->first(); $cawangan = Cawangan::on('mysql7')->where('kodcaw','=',$request->kodcaw)->first();
$latestbatch = SerahBaki::on($cawangan['mysql'])->where('norujukan','baru')->get()->toArray(); //$latestbatch = SerahBaki::on($cawangan['mysql'])->where('norujukan','baru')->get()->toArray();
//new added
$serahBaki = SerahBaki::on($cawangan['mysql'])
->where('norujukan', 'baru')
->get();
$allBatchNo = $serahBaki->pluck('batchno')->unique()->toArray();
$wtddraftData = WTDDraft::on('mysql7')
->selectRaw("
batchno_serah,
YEAR(t_jual) as tahun,
GROUP_CONCAT(
DISTINCT MONTH(t_jual)
ORDER BY MONTH(t_jual)
SEPARATOR ','
) as bulan
")
->where('kodcaw', $request->kodcaw)
->whereIn('batchno_serah', $allBatchNo)
->groupBy('batchno_serah', DB::raw('YEAR(t_jual)'))
->get()
->groupBy('batchno_serah')
->map(function ($rows) {
return $rows->map(function ($row) {
return [
'tahun' => $row->tahun,
'bulan' => $row->bulan
];
})->values();
});
$finalData = $serahBaki->map(function ($item) use ($wtddraftData) {
$batchno = $item->batchno;
$tahun = null;
$bulan = [];
if (!empty($wtddraftData[$batchno])) {
// ambil tahun pertama (kebiasaannya satu tahun sahaja)
$tahun = $wtddraftData[$batchno][0]['tahun'];
// convert string "2,3,4,5" → array
$bulan = explode(',', $wtddraftData[$batchno][0]['bulan']);
}
return [
'batchno' => $batchno,
'norujukan' => $item->norujukan,
'tarikh' => $item->tarikh,
't_jual' => $item->t_jual,
'baki' => $item->baki,
't_htr_ag' => $item->t_htr_ag,
'aktif' => $item->aktif,
'tahun' => $tahun,
'bulan' => implode(',',$bulan),
// field lain kekal
];
});
$finalDataArray = $finalData->toArray();
//end new added
$batch_old = WTDDraft::on('mysql7')->select('kodcaw')->where('batchno_serah',0)->where('kodcaw',$request->kodcaw) $batch_old = WTDDraft::on('mysql7')->select('kodcaw')->where('batchno_serah',0)->where('kodcaw',$request->kodcaw)
->groupBy('kodcaw')->get(); ->groupBy('kodcaw')->get();
$batch_old_noruj = WTDDraft::on('mysql7')->where('batchno_serah',0)->where('kodcaw',$request->kodcaw)->pluck('norujukan'); $batch_old_noruj = WTDDraft::on('mysql7')->where('batchno_serah',0)->where('kodcaw',$request->kodcaw)->pluck('norujukan');
$lelong_data = Lelong::on($cawangan['mysql'])->whereIn('norujukan',$batch_old_noruj)->get(); $lelong_data = Lelong::on($cawangan['mysql'])->whereIn('norujukan',$batch_old_noruj)->get();
foreach($batch_old as $index=>$bo) foreach($batch_old as $index=>$bo)
{ {
array_push($latestbatch,['recno' => 0,'norujukan' => 'lama','batchno' => 0,'baki' => $lelong_data->sum('baki'),'aktif' => 1]); //array_push($latestbatch,['recno' => 0,'norujukan' => 'lama','batchno' => 0,'baki' => $lelong_data->sum('baki'),'aktif' => 1]);
array_push($finalDataArray,['recno' => 0,'norujukan' => 'lama','batchno' => 0,'baki' => $lelong_data->sum('baki'),'aktif' => 1]);
} }
$data = $this->paginate($latestbatch,8); //$data = $this->paginate($latestbatch,8);
$data = $this->paginate($finalDataArray,8);
return response()->json($data,200); return response()->json($data,200);
@@ -2698,8 +2763,9 @@ class AdminPageController extends Controller
't_update' => $current->toDateString())); 't_update' => $current->toDateString()));
} }
$serahbakiupdate = SerahBaki::on($cawangan['mysql'])->where('batchno',$batchno)->update(array('aktif' => 1,'t_jual' => $current->toDateString(),'nopelanggan' => $request->nocek));; //$serahbakiupdate = SerahBaki::on($cawangan['mysql'])->where('batchno',$batchno)->update(array('aktif' => 1,'t_jual' => $current->toDateString(),'nopelanggan' => $request->nocek));;
$serahbakiupdate = SerahBaki::on($cawangan['mysql'])->where('batchno',$batchno)->update(array('aktif' => 1,'t_jual' => $current->toDateString(),'nopelanggan' => $request->nocek,'t_htr_ag' => $request->tarikhAG));
return response()->json('success',200); return response()->json('success',200);
}catch (\Throwable $e){ }catch (\Throwable $e){
@@ -3160,8 +3226,6 @@ class AdminPageController extends Controller
return response()->json($customers); return response()->json($customers);
} }
public function AkruKeuntunganSebenar(Request $request){ public function AkruKeuntunganSebenar(Request $request){
@@ -3760,16 +3824,16 @@ class AdminPageController extends Controller
$get_imbangduga = imbangdugabackup::on($cawangan['mysql'])->where('tarikh', $lastDayOfYear)->first(); $get_imbangduga = imbangdugabackup::on($cawangan['mysql'])->where('tarikh', $lastDayOfYear)->first();
$get_imbangduga = optional($get_imbangduga)->toArray() ?? []; $get_imbangduga = optional($get_imbangduga)->toArray() ?? [];
if(empty($get_imbangduga)){ // if(empty($get_imbangduga)){
$requestData = new Request([ // $requestData = new Request([
'tarikh' => $request->tarikh, // 'tarikh' => $request->tarikh,
'kodcaw' => $kodcaw, // 'kodcaw' => $kodcaw,
]); // ]);
$exception_case = $this->AkruKeuntunganSebenar($requestData); // $exception_case = $this->AkruKeuntunganSebenar($requestData);
} // }
$backdate_keun_sebenar += isset($get_imbangduga['keun_sebenar']) ? $get_imbangduga['keun_sebenar'] : 0; $backdate_keun_sebenar += isset($get_imbangduga['keun_sebenar']) ? $get_imbangduga['keun_sebenar'] : 0;
$backdate_keun_sebenar += $exception_case; $backdate_keun_sebenar += (float) ($exception_case ?? 0);
$recentDate->subYear()->startOfYear(); $recentDate->subYear()->startOfYear();
} }
@@ -3785,14 +3849,7 @@ class AdminPageController extends Controller
$total = ($utgrugilama + $lelong + $upahsimpantebus + $upahsimpanlelong + $upahsimpanansur + $gstcajlelong + $keuntungansebenar + $upahsimpankeuntungansebelumtawarruq + $available_akru + $total_keuntungan_sebenar + $akru_ujrah + $akru_1percent) + $parameter; $total = ($utgrugilama + $lelong + $upahsimpantebus + $upahsimpanlelong + $upahsimpanansur + $gstcajlelong + $keuntungansebenar + $upahsimpankeuntungansebelumtawarruq + $available_akru + $total_keuntungan_sebenar + $akru_ujrah + $akru_1percent) + $parameter;
if($kodcaw == '011229') if($kodcaw == '011229')
$total -= 45390.37; $total -= 45390.37;
if($kodcaw == 'KB2')
$total -= 64.8;
$total += Penyelarasan::on('mysql7')
->where('kodcaw', $kodcaw)
->sum(DB::raw('rugilelong + bakilelong + `lain-lain`'));
return response()->json($total,200); return response()->json($total,200);
} }
@@ -3965,4 +4022,222 @@ class AdminPageController extends Controller
'result' => $status === 'completed' ? $result : null, 'result' => $status === 'completed' ? $result : null,
]); ]);
} }
//function wtd baru
public function janaSimulasiWTD(Request $request)
{
$cawangan = Cawangan::on('mysql7')->where('kodcaw', '=', $request->kodcaw)->first();
//listing sag belum tuntut cwgn
$sag_cwgn = collect(
Lelong::on($cawangan['mysql'])
->selectRaw('norujukan')
->whereYear('t_jual', $request->tahun)
->whereNull('trkhtuntut')
->where('baki', '>', 0)
->pluck('norujukan') // lebih bersih
);
//listing sag blocked
$sag_online = collect(
WTDDraft::on('mysql7')
->selectRaw('norujukan')
->where('kodcaw', '=', $request->kodcaw)
->pluck('norujukan')
);
//dd($sag_online);
//filter sag yg tk wujud dlm wtd_draft
$filtersag = $sag_cwgn->diff($sag_online);
//query baru
$tarikh_belum_tuntut = Lelong::on($cawangan['mysql'])
->selectRaw('
MONTH(t_jual) as bulan,
SUM(pinjaman) as pembiayaan,
ABS(SUM(baki)) as baki,
COUNT(DISTINCT norujukan) as jumlah_norujukan,
kodcaw
')
->whereIn('norujukan', $filtersag)
->groupBy('bulan', 'kodcaw')
->orderBy('bulan')
->get();
$tarikh_belum_tuntut = $tarikh_belum_tuntut->map(function ($item) {
$item->bulan = \Carbon\Carbon::create()->month($item->bulan)->format('F');
return $item;
});
return response()->json($tarikh_belum_tuntut);
}
public function RekodSimulasiWTD(Request $request)
{
$cawangan = Cawangan::on('mysql7')->where('kodcaw', '=', $request->kodcaw)->first();
$rekod_simulasi = Lelong::on($cawangan['mysql'])
->join('gadai','lelong.norujukan','=','gadai.norujukan')
->selectRaw('ABS(lelong.baki) as baki, lelong.t_lelong, lelong.pinjaman, lelong.norujukan, gadai.nokp')
->whereMonth('lelong.t_jual', $request->month)
->whereYear('lelong.t_jual', $request->year)
->whereNull('lelong.trkhtuntut')
->where('lelong.baki', '>', 0)
->get();
return response()->json($rekod_simulasi);
}
public function prosesSimulasiWTD(Request $request)
{
$proses = $request->input;
// dd($proses, $cawangan);
$baki = 0;
$jumlahPembiayaan = 0;
$simulasi = WTDSimulasi::max('simulasi')+1;
foreach ($proses as $item) {
WTDSimulasi::create([
'bulan' => $item['bulan'],
'tahun' => $item['tahun'],
'kodcaw' => $item['kodcaw'],
'jumlah_sag' => $item['jumlah_sag'],
'pembiayaan'=> $item['pembiayaan'],
'baki'=> $item['baki'],
'simulasi' => $simulasi,
]);
$baki += $item['baki'];
$jumlahPembiayaan = $item['pembiayaan'];
}
return response()->json(['status' => 'success','simulasi' => $simulasi,'baki' => $baki,'pinjaman' => $jumlahPembiayaan]);
}
public function pengesahanSimulasiWTD(Request $request)
{
// Decode the JSON records from the request
$records = json_decode($request->records, true);
// Retrieve and clean 'kodcaw' from the request
$kodcaw = $request->kodcaw;
$kodcaw_clean = str_replace('"', '', $kodcaw);
// Get the database connection for the branch (cawangan)
$cawangan = Cawangan::where('kodcaw', $kodcaw_clean)->first();
// Check if 'Cawangan' exists
if (!$cawangan) {
return response()->json(['status' => 'error', 'message' => 'Invalid branch code (kodcaw).'], 404);
}
$cawangan_connection = $cawangan->mysql;
// Get the latest batch number and increment it
$latestBatch = SerahBaki::on($cawangan_connection)->max('batchno') + 1;
// Initialize total variables
$totalPembiayaan = 0;
$totalBaki = 0;
try {
// Iterate through the records and save them to the WTDDraft table
foreach ($records as $record) {
// Check if 'bulan' and 'tahun' exist in the record
if (!isset($record['bulan']) || !isset($record['tahun'])) {
return response()->json(['status' => 'error', 'message' => 'Missing bulan or tahun in records.'], 400);
}
$month = DateTime::createFromFormat('F', $record["bulan"])->format('n');
// Query norujukan records from the database
$query_norujukan = Lelong::on($cawangan_connection)
->join('gadai', 'lelong.norujukan', '=', 'gadai.norujukan')
->selectRaw('ABS(lelong.baki) as baki, lelong.t_lelong, lelong.pinjaman, lelong.norujukan, gadai.nokp, lelong.t_jual')
->whereMonth('lelong.t_jual', $month)
->whereYear('lelong.t_jual', $record["tahun"])
->whereNull('lelong.trkhtuntut')
->where('lelong.baki', '>', 0)
->get();
// Save each record to the WTDDraft table
foreach ($query_norujukan as $query) {
$wtddraft = new WTDDraft();
$wtddraft->nokp = $query['nokp'];
$wtddraft->kodcaw = $kodcaw_clean;
$wtddraft->norujukan = $query['norujukan'];
$wtddraft->t_jual = $query['t_jual'];
$wtddraft->t_gadai = $query['t_gadai'] ?? null; // Optional: ensure 't_gadai' exists
$wtddraft->t_lelong = $query['t_lelong'];
$wtddraft->batchno_serah = $latestBatch;
$wtddraft->save();
}
// Accumulate totals
$totalPembiayaan += $record['pembiayaan'] ?? 0;
$totalBaki += $record['baki'] ?? 0;
}
// Create a new record in the SerahBaki table
SerahBaki::on($cawangan_connection)->create([
'norujukan' => 'baru',
'batchno' => $latestBatch,
'hargajual' => 0.00,
'pinjaman' => $totalPembiayaan,
'upah' => 0.00,
'cajlel' => 0.00,
'gst_cl' => 0.00,
'gst_hj' => 0.00,
'baki' => $totalBaki,
'tarikh' => Carbon::now()->toDateString(),
't_jual' => Carbon::now()->toDateString(),
'nopelanggan' => '',
'aktif' => 0,
]);
// Return a success response with the new batch number
return response()->json(['status' => 'success', 'batchno' => $latestBatch], 200);
} catch (\Throwable $e) {
// Log the error and return a failure response
Log::error($e->getMessage());
Log::error($e->getLine());
return response()->json(['status' => 'error', 'message' => $e->getMessage()], 500);
}
}
public function simulasiToDraft(Request $request)
{
$bulan = $request->bulan;
if (!$bulan || count($bulan) === 0) {
return response()->json(['error' => 'Sila pilih sekurang-kurangnya satu bulan.'], 400);
}
$simulasi = WTDSimulasi::whereIn('bulan', $bulan)->get();
if ($simulasi->isEmpty()) {
return response()->json(['error' => 'Tiada data untuk bulan yang dipilih.'], 404);
}
// foreach ($simulasi as $data) {
// WTDDraft::create([
// 'nokp' => $data->nokp ?? null,
// 'kodcaw' => $data->kodcaw ?? null,
// 'norujukan' => $data->norujukan ?? null,
// 't_jual' => $data->t_jual ?? null,
// 't_gadai' => $data->t_gadai ?? null,
// 't_lelong' => $data->t_lelong ?? null,
// 'batchno_serah' => $data->simulasi, // Simpan sebagai rujukan
// ]);
// }
//dd($bulan, $simulasi);
return response()->json(['message' => 'Data berjaya dipindahkan ke WTD Draft!']);
}
} }
@@ -331,7 +331,7 @@ class BackupStokAuditController extends Controller
} }
public function kiraupahTawarruqStokAudit($tempoh,$tempohbayar,$kadarupah,$bakipinjaman){ public function kiraupahTawarruqStokAudit($tempoh,$tempohbayar,$kadarupah,$bakipinjaman){
$tempoh = ($tempoh > 12) ? 12 : $tempoh;
$bilang_bln = $tempoh - $tempohbayar; $bilang_bln = $tempoh - $tempohbayar;
if($bilang_bln > 12){ if($bilang_bln > 12){
@@ -458,6 +458,7 @@ class BackupStokAuditController extends Controller
public function kiraupahTawarruqStokAuditUjrahOnePercent($tempoh,$tempohbayar,$kadarupah,$bakipinjaman,$nilaimarhun,$margin_semasa){ public function kiraupahTawarruqStokAuditUjrahOnePercent($tempoh,$tempohbayar,$kadarupah,$bakipinjaman,$nilaimarhun,$margin_semasa){
$onepercentservices = new V2Calculation(); $onepercentservices = new V2Calculation();
$upah = $onepercentservices->kiraanKeuntunganRebet($bakipinjaman,$nilaimarhun,$kadarupah,$margin_semasa); $upah = $onepercentservices->kiraanKeuntunganRebet($bakipinjaman,$nilaimarhun,$kadarupah,$margin_semasa);
$tempoh = ($tempoh > 12) ? 12 : $tempoh;
$bilang_bln = $tempoh - $tempohbayar; $bilang_bln = $tempoh - $tempohbayar;
$keuntungan_semasa = $bilang_bln * $upah['onepercent']; $keuntungan_semasa = $bilang_bln * $upah['onepercent'];
$ujrah_semasa = $bilang_bln * $upah['ujrah']; $ujrah_semasa = $bilang_bln * $upah['ujrah'];
+171 -19
View File
@@ -6,38 +6,190 @@ use App\Audit;
use App\Polis; use App\Polis;
use App\Cawangan; use App\Cawangan;
use App\LookupAlasan; use App\LookupAlasan;
use App\Palsu;
use App\Gadai;
use App\Pampasan;
use Illuminate\Http\Request; use Illuminate\Http\Request;
use Carbon\Carbon; use Carbon\Carbon;
use Illuminate\Support\Facades\DB; use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Http;
use Illuminate\Support\Facades\Log;
class BarangkesController extends Controller class BarangkesController extends Controller
{ {
public function LaporanBarangKes(Request $request) public function LaporanBarangKes(Request $request)
{ {
$status = $request->status;
$cawangan = Cawangan::on('mysql7')->where('kodcaw', $request->kodcaw)->first(); $cawangan = Cawangan::on('mysql7')->where('kodcaw', $request->kodcaw)->first();
if (!$cawangan) { if (!$cawangan) {
return response()->json(['error' => 'Invalid kodcaw'], 403); return response()->json(['error' => 'Invalid kodcaw'], 403);
}
$palsu_query = Palsu::on($cawangan['mysql'])
->select([
'tarikh',
'norujukan',
'nota',
'pembiayaan',
'nilaimarhun',
'jbg',
'untung',
'untungonepercent',
'untungcajlain'
])
->when($request->filled('tarikh_mula') && $request->filled('tarikh_akhir'), function ($query) use ($request) {
return $query->whereBetween('tarikh', [$request->tarikh_mula, $request->tarikh_akhir]);
})
->with(['tebus:norujukan', 'gadai:norujukan,nokp']);
$palsu_array = $palsu_query->get()->toArray();
$pampasan_array = Pampasan::on($cawangan['mysql'])->where('kodcaw', $request->kodcaw)->get()->toArray();
$indexedArray2 = collect($pampasan_array)->keyBy('norujukan');
$merged = collect($palsu_array)->map(function ($item) use ($indexedArray2) {
$id = $item['norujukan'];
$itemArray = $item; // Already an array from toArray()
$additional = $indexedArray2->get($id, []);
// Add exists_in_tebus flag based on relationship
$itemArray['gadaian_sudah_tebus'] = !is_null($item['tebus']);
// Add nokp customer from gadai relationship
$itemArray['nokp'] = $item['gadai']['nokp'] ?? null;
// Remove the tebus relationship data to keep response clean
unset($itemArray['tebus']);
unset($itemArray['gadai']);
return array_merge($itemArray, $additional);
})->values()->toArray();
$filteredResults = [];
$sudahTuntutSecaraManual = [
'011237240719-0015',
'011237240806-0011',
'011237240828-0001',
'011237240731-0026',
'011237240912-0009'
];
// if ($status == 'dituntut') {
// foreach ($merged as $pampasan) {
// if (isset($pampasan['status']) && $pampasan['status'] == 1) {
// $filteredResults[] = $pampasan;
// }
// }
// }
if ($status == 'dituntut') {
foreach ($merged as $pampasan) {
if (
(isset($pampasan['status']) && $pampasan['status'] == 1)
|| in_array($pampasan['norujukan'], $sudahTuntutSecaraManual)
) {
$filteredResults[] = $pampasan;
}
}
}
// if ($status == 'belum-tuntut') {
// foreach ($merged as $pampasan) {
// if (!isset($pampasan['status'])) {
// $filteredResults[] = $pampasan;
// }
// }
// }
if ($status == 'belum-tuntut') {
foreach ($merged as $pampasan) {
if (
!isset($pampasan['status'])
&& !in_array($pampasan['norujukan'], $sudahTuntutSecaraManual)
) {
$filteredResults[] = $pampasan;
}
}
}
if ($status == 'all' || $status == null) {
$filteredResults = $merged;
}
return response()->json($filteredResults);
} }
$query = DB::connection($cawangan['mysql'])->table('palsu') public function store(Request $request) //cara fifi ajar
->select([ {
'tarikh',
'norujukan',
'nota',
'pembiayaan',
'nilaimarhun',
'jbg',
'untung',
'untungonepercent',
'untungcajlain'
])
->whereBetween('tarikh', [$request->tarikh_mula, $request->tarikh_akhir]);
$result = $query->get(); $current = Carbon::now();
$kodcaw = $request->kodcaw;
$cawangan = Cawangan::on('mysql7')
->where('kodcaw', $kodcaw)
->first();
return response()->json($result); $insert = Palsu::on($cawangan['mysql'])->create([
'kodcaw' => $request->kodcaw,
'tarikh' => $current->toDateString(),
'norujukan' => $request->norujukan,
'teller' => $request->teller,
'nota' => $request->nota ? $request->nota : '',
'pembiayaan' => $request->pinjaman,
'nilaimarhun' => $request->nilaimarhun,
'jbg' => $request->jbg,
'untung' => $request->tunggakan,
'untungonepercent' => $request->tunggakanonepercent,
'untungcajlain' => $request->tunggakanujrah,
]);
// return $insert;
return response()->json([
'success' => true,
'message' => 'Barang kes berjaya didaftar',
'data' => $insert
], 201);
}
public function update(Request $request)
{
$current = Carbon::now();
$kodcaw = $request->kodcaw;
Log::info($request->all());
// Cari connection cawangan
$cawangan = Cawangan::on('mysql7')
->where('kodcaw', $kodcaw)
->first();
if (!$cawangan) {
return response()->json([
'success' => false,
'message' => 'Cawangan tidak dijumpai',
], 404);
}
// Update direct (ikut norujukan)
$palsu = palsu::on($cawangan['mysql'])
->where('norujukan', $request->norujukan)
->update([
'kodcaw' => $request->kodcaw,
'tarikh' => $request->tarikh,
'teller' => $request->teller,
'nota' => $request->nota ?? '',
'pembiayaan' => $request->pinjaman,
'nilaimarhun' => $request->nilaimarhun,
'jbg' => $request->jbg,
'untung' => $request->tunggakan,
'untungonepercent' => $request->tunggakanonepercent,
'untungcajlain' => $request->tunggakanujrah,
]);
return response()->json([
'success' => $palsu ? true : false,
'message' => $palsu ? 'Rekod gadai berjaya dikemaskini' : 'Rekod tidak dijumpai',
], 200);
}
} }
}
+11 -1
View File
@@ -3,6 +3,7 @@
namespace App\Http\Controllers; namespace App\Http\Controllers;
use App\Cawangan; use App\Cawangan;
use App\Feature;
use Illuminate\Http\Request; use Illuminate\Http\Request;
class CawanganController extends Controller class CawanganController extends Controller
@@ -18,7 +19,16 @@ class CawanganController extends Controller
$cawangan = Cawangan::on('mysql7') $cawangan = Cawangan::on('mysql7')
->where('kodcaw','=',$code_cawangan) ->where('kodcaw','=',$code_cawangan)
->first(); ->first();
return response()->json($cawangan);
if (!$cawangan) {
return response()->json($cawangan);
}
$data = $cawangan->toArray();
$data['features'] = Feature::mapFor($code_cawangan);
$data['api_arrahnbid'] = Feature::arrahnbidUrl($code_cawangan);
return response()->json($data);
} }
public function create(Request $request) public function create(Request $request)
+255 -25
View File
@@ -5,6 +5,7 @@ namespace App\Http\Controllers;
use App\Audit; use App\Audit;
use App\Marhun; use App\Marhun;
use App\BankMaster; use App\BankMaster;
use App\ARFiles;
use App\Customer; use App\Customer;
use App\Gadai; use App\Gadai;
use App\Lelong; use App\Lelong;
@@ -14,6 +15,7 @@ use App\Blacklist;
use App\AuditCustomer; use App\AuditCustomer;
use Illuminate\Http\Request; use Illuminate\Http\Request;
use App\TuntutBaki; use App\TuntutBaki;
use Illuminate\Support\Facades\Auth;
use App\Anggota; use App\Anggota;
use Carbon\Carbon; use Carbon\Carbon;
@@ -63,7 +65,7 @@ class CustomerController extends Controller
->orWhere('kpbaru','=',$ic) ->orWhere('kpbaru','=',$ic)
->first(); ->first();
return response()->json($customer); return response()->json($this->withMykadPhoto($customer));
} }
public function showOneCustomerByICAdmin(Request $request){ public function showOneCustomerByICAdmin(Request $request){
@@ -73,7 +75,7 @@ class CustomerController extends Controller
->orWhere('kpbaru','=',$request->ic) ->orWhere('kpbaru','=',$request->ic)
->first(); ->first();
return response()->json($customer); return response()->json($this->withMykadPhoto($customer));
} }
public function showOneCustomerByICMobile($ic){ public function showOneCustomerByICMobile($ic){
@@ -367,6 +369,8 @@ class CustomerController extends Controller
'tujuangadai'=>$request->tujuangadai 'tujuangadai'=>$request->tujuangadai
]); ]);
$this->attachMykadPhoto($customer, $request);
$audit = new Audit(); $audit = new Audit();
$audit->users = $request->teller; $audit->users = $request->teller;
$audit->actions = "Daftar Pelanggan Baru"; $audit->actions = "Daftar Pelanggan Baru";
@@ -376,7 +380,7 @@ class CustomerController extends Controller
$audit->updated_at = $current; $audit->updated_at = $current;
$audit->save(); $audit->save();
return response()->json($customer, 201); return response()->json($this->withMykadPhoto($customer), 201);
} }
public function customerUpdate($nokp,Request $request){ public function customerUpdate($nokp,Request $request){
@@ -395,37 +399,38 @@ class CustomerController extends Controller
// 'nota_arcc'=>$request->nota_arcc, // 'nota_arcc'=>$request->nota_arcc,
'telefon' => $request->telefon1, 'telefon' => $request->telefon1,
'telefon2' => $request->telefon2, 'telefon2' => $request->telefon2,
'telefon2' => $request->telefon2,
)); ));
return response()->json($customer_update, 200); return response()->json($customer_update, 200);
} }
public function assignAnggota($noic, Request $request) public function assignAnggota($noic, Request $request)
{ {
// Semak sama ada pelanggan wujud // Semak sama ada pelanggan wujud
$customer = Customer::on('mysql7') $customer = Customer::on('mysql7')
->where('kpbaru', $noic) ->where('kpbaru', $noic)
->orWhere('kplama', $noic) ->orWhere('kplama', $noic)
->first(); ->first();
if (!$customer) {
return response()->json([
'success' => false,
'message' => 'Pelanggan tidak dijumpai.'
], 404);
}
// Kemaskini tag_anggota
$customer->tag_anggota = 1;
$customer->save();
if (!$customer) {
return response()->json([ return response()->json([
'success' => false, 'success' => true,
'message' => 'Pelanggan tidak dijumpai.' 'message' => 'Tag anggota berjaya dikemaskini.',
], 404); 'data' => $customer
], 200);
} }
// Kemaskini tag_anggota
$customer->tag_anggota = 1;
$customer->save();
return response()->json([
'success' => true,
'message' => 'Tag anggota berjaya dikemaskini.',
'data' => $customer
], 200);
}
public function customerUpdateKaunter($nokp,$kodcaw, Request $request){ public function customerUpdateKaunter($nokp,$kodcaw, Request $request){
$current = Carbon::now(); $current = Carbon::now();
@@ -746,7 +751,7 @@ class CustomerController extends Controller
$customer = Customer::on($cawangan['mysql']) $customer = Customer::on($cawangan['mysql'])
->where('kplama','=',$nokp) ->where('kplama','=',$nokp)
->orWhere('kpbaru','=',$nokp) ->orWhere('kpbaru','=',$nokp)
->rightJoin('online_arrahn.bank', 'bank.id', '=', 'customer.kodbank') ->rightJoin(config('tennant_database.master_db') . '.bank', 'bank.id', '=', 'customer.kodbank')
->first(); ->first();
if(!empty($customer)) if(!empty($customer))
@@ -939,6 +944,69 @@ class CustomerController extends Controller
return response()->json($customer); return response()->json($customer);
} }
public function AdminsearchCustomerBySAG(Request $request)
{
// Ambil kodcaw dari user login
$kodcaw = $request->kodcaw;
// $norujukan = $request->input('norujukan');
// Cari connection untuk cawangan
$cawangan = Cawangan::on('mysql7')->where('kodcaw', $kodcaw)->first();
if (!$cawangan) {
return response()->json([], 404);
}
$gadai = optional(Gadai::on($cawangan['mysql'])->where('norujukan',$request->norujukan)->first())->toArray() ?? [];
if(!empty($gadai)){
$customer = optional(Customer::on('mysql7')->where(function ($query) use ($gadai) {
$query->where('kpbaru',$gadai['nokp'])
->orWhere('kplama',$gadai['nokp']);
})->first())->toArray() ?? [];
}else{
return response()->json(['success' => false,'message' => 'norujukan tidak dijumpainya'], 404);
}
// cara fifi ajar
$result = [[
'id' => $customer['id'],
'kodcaw' => $gadai['kodcaw'],
'norujukan' => $gadai['norujukan'],
'teller' => $gadai['teller'],
'nota' => $customer['nota'],
'pinjaman' => $gadai['pinjaman'],
'nilaimarhun' => $gadai['nilaimarhun'],
'jbg' => $gadai['jbg'],
'tunggakan' => $gadai['tunggakan'],
'tunggakanonepercent' => $gadai['tunggakanonepercent'],
'tunggakanujrah' => $gadai['tunggakanujrah'],
'nama' => $customer['nama'],
'kplama' => $customer['kplama'],
'kpbaru' => $customer['kpbaru'],
]];
// saya buat sendiri
// Join customer + gadai ikut nokp
// $result = DB::connection($cawangan['mysql'])
// ->table('gadai')
// ->join('online_arrahn.customer as c', function($join) {
// $join->on('gadai.nokp', '=', 'c.kpbaru')
// ->orOn('gadai.nokp', '=', 'c.kplama');
// })
// ->where('norujukan', $request->norujukan)
// ->select(
// 'id',
// 'gadai.kodcaw','gadai.norujukan','gadai.teller',
// 'c.nota','gadai.pinjaman','gadai.nilaimarhun','gadai.jbg',
// 'gadai.tunggakan','gadai.tunggakanonepercent','gadai.tunggakanujrah',
// 'c.nama','c.kpbaru','c.kplama'
// )
// ->take(5)
// ->get();
return response()->json($result);
}
public function changepassword(Request $request, $kodcaw, $id) { public function changepassword(Request $request, $kodcaw, $id) {
$current = Carbon::now(); $current = Carbon::now();
@@ -1038,6 +1106,168 @@ class CustomerController extends Controller
return response()->json($results); return response()->json($results);
} }
public function updateTagPdpa(Request $request)
{
$tarikh_cetak_pdpa = Carbon::now()->toDateString();
$no_ic = $request->input('no_ic');
$customer = Customer::where('kplama', $no_ic)
->orWhere('kpbaru', $no_ic)
->first();
if (!$customer) {
return response()->json(['error' => 'Customer not found.'], 404);
}
$customer->tag_pdpa = $request->input('tag_pdpa');
$customer->tarikh_cetak_pdpa = $tarikh_cetak_pdpa;
$customer->save();
return response()->json(['message' => 'Customer PDPA updated successfully.'], 200);
}
/**
* Store MyKad photo for an existing customer only when gambar_mykad is empty.
*/
public function storeMykadPhotoIfMissing($ic, Request $request)
{
$customer = Customer::on('mysql7')
->where('kplama', '=', $ic)
->orWhere('kpbaru', '=', $ic)
->first();
if (!$customer) {
return response()->json(['error' => 'Customer not found.', 'stored' => false], 404);
}
if (!empty($customer->gambar_mykad)) {
return response()->json([
'message' => 'MyKad photo already stored.',
'gambar_mykad' => $customer->gambar_mykad,
'stored' => false,
], 200);
}
$this->attachMykadPhoto($customer, $request);
return response()->json([
'message' => !empty($customer->gambar_mykad)
? 'MyKad photo stored.'
: 'No photo provided or store failed.',
'gambar_mykad' => $customer->gambar_mykad,
'stored' => !empty($customer->gambar_mykad),
], 200);
}
/**
* Save MyKad photo into arrahn_files and link it on customer.gambar_mykad.
*/
protected function attachMykadPhoto($customer, Request $request)
{
if (!$customer) {
return;
}
$raw = $this->photoBase64FromRequest($request);
if ($raw === '') {
return;
}
try {
$fileId = $this->storeMykadPhoto($raw, $request->input('photo_mime', $request->json('photo_mime')), $customer);
if (!$fileId) {
return;
}
Customer::on('mysql7')
->where('kpbaru', $customer->kpbaru)
->where('kplama', $customer->kplama)
->update(['gambar_mykad' => $fileId]);
$customer->gambar_mykad = $fileId;
} catch (\Throwable $e) {
Log::error('Failed to attach MyKad photo: ' . $e->getMessage());
}
}
protected function photoBase64FromRequest(Request $request)
{
$raw = $request->input('photo_base64');
if ($raw === null || $raw === '') {
$raw = $request->json('photo_base64');
}
return is_string($raw) ? $raw : '';
}
protected function storeMykadPhoto($raw, $mime, $customer)
{
$commaPos = strpos($raw, ',');
if ($commaPos !== false) {
$raw = substr($raw, $commaPos + 1);
}
$raw = preg_replace('/\s+/', '', $raw);
if ($raw === '') {
return null;
}
$decoded = base64_decode($raw, true);
if ($decoded === false) {
$decoded = base64_decode($raw);
}
if ($decoded === false || $decoded === '') {
Log::warning('MyKad photo skipped: invalid base64');
return null;
}
if (strlen($raw) > 400000) {
Log::warning('MyKad photo skipped: payload too large');
return null;
}
$mime = strtolower((string) ($mime ?: 'image/jpeg'));
if (!in_array($mime, ['image/jpeg', 'image/jpg', 'image/png'], true)) {
$mime = 'image/jpeg';
}
$nric = preg_replace('/[^0-9A-Za-z]/', '', (string) ($customer->kpbaru ?: ''));
$ext = $mime === 'image/png' ? 'png' : 'jpg';
$file = new ARFiles();
$file->data = $raw;
$file->filename = ($nric !== '' ? $nric : 'mykad') . '.' . $ext;
$file->type = $mime;
$file->tarikhmasa = Carbon::now()->toDateTimeString();
$file->save();
return $file->id;
}
protected function withMykadPhoto($customer)
{
if (!$customer) {
return $customer;
}
$payload = $customer->toArray();
$payload['photo_base64'] = null;
$payload['photo_mime'] = null;
if (empty($customer->gambar_mykad)) {
return $payload;
}
$file = ARFiles::on('mysql7')->where('id', $customer->gambar_mykad)->first();
if ($file && $file->data) {
$payload['photo_base64'] = $file->data;
$payload['photo_mime'] = $file->type ?: 'image/jpeg';
}
return $payload;
}
// public function createNotaArcc($kodcaw, Request $request) // public function createNotaArcc($kodcaw, Request $request)
// { // {
// $current = Carbon::now(); // $current = Carbon::now();
@@ -0,0 +1,59 @@
<?php
namespace App\Http\Controllers;
use App\Cawangan;
use App\Feature;
use Illuminate\Http\Request;
class FeatureController extends Controller
{
public function index()
{
return response()->json([
'keys' => Feature::keys(),
'labels' => Feature::labels(),
]);
}
public function cawangan()
{
$cawangan = Cawangan::on('mysql7')
->orderBy('kodcaw')
->get(['kodcaw', 'details_caw']);
$maps = Feature::mapForMany($cawangan->pluck('kodcaw')->all());
$data = $cawangan->map(function ($c) use ($maps) {
return [
'kodcaw' => $c->kodcaw,
'details_caw' => $c->nama_cawangan,
'features' => $maps[$c->kodcaw] ?? Feature::defaults(),
];
});
return response()->json($data);
}
public function update($kodcaw, $feature, Request $request)
{
$cawangan = Cawangan::on('mysql7')->where('kodcaw', $kodcaw)->first();
if (!$cawangan) {
return response()->json(['message' => 'Cawangan tidak dijumpai'], 404);
}
if (!in_array($feature, Feature::keys(), true)) {
return response()->json(['message' => 'Ciri tidak sah'], 422);
}
$enabled = (int) $request->input('enabled') ? 1 : 0;
Feature::setEnabled($kodcaw, $feature, $enabled);
return response()->json([
'kodcaw' => $kodcaw,
'feature' => $feature,
'enabled' => $enabled,
'features' => Feature::mapFor($kodcaw),
]);
}
}
+79 -36
View File
@@ -29,6 +29,7 @@ use App\KomuditiTransaksi;
use App\Advansur; use App\Advansur;
use App\HistoryEmasSandaran; use App\HistoryEmasSandaran;
use App\InOutMar; use App\InOutMar;
use App\Services\Miscellaneous\StatistikService;
use Illuminate\Http\Request; use Illuminate\Http\Request;
@@ -536,7 +537,7 @@ class GadaiController extends Controller
public function getLaporanGadai($kodcaw,$tarikh){ public function getLaporanGadai($kodcaw,$tarikh){
$cawangan = Cawangan::on('mysql7')->where('kodcaw','=',$kodcaw)->first(); $cawangan = Cawangan::on('mysql7')->where('kodcaw','=',$kodcaw)->first();
$gadai_data = Gadai::on($cawangan['mysql'])->select('t_gadai','norujukan','nokp','semakbarcode','masa','berat','nilaimarhun','pinjaman','upah12','percentpinj','teller','nokp','ujrah','onepercent') $gadai_data = Gadai::on($cawangan['mysql'])->select('cara_terima','t_gadai','norujukan','nokp','semakbarcode','masa','berat','nilaimarhun','pinjaman','upah12','percentpinj','teller','nokp','ujrah','onepercent','kadarrebet','diskaun')
->where('t_gadai','=',$tarikh) ->where('t_gadai','=',$tarikh)
->orderBy('teller') ->orderBy('teller')
->orderBy('sirig') ->orderBy('sirig')
@@ -550,6 +551,7 @@ class GadaiController extends Controller
array_push($gadai,[ array_push($gadai,[
"t_gadai"=> $gadaiData['t_gadai'], "t_gadai"=> $gadaiData['t_gadai'],
"norujukan"=> $gadaiData['norujukan'], "norujukan"=> $gadaiData['norujukan'],
"cara_terima"=> $gadaiData['cara_terima'],
"nama"=> $customer_info['nama'], "nama"=> $customer_info['nama'],
"nokp"=> $gadaiData['nokp'], "nokp"=> $gadaiData['nokp'],
"semakbarcode"=> $gadaiData['semakbarcode'], "semakbarcode"=> $gadaiData['semakbarcode'],
@@ -562,7 +564,9 @@ class GadaiController extends Controller
"alamat1"=> $customer_info['alamat1'], "alamat1"=> $customer_info['alamat1'],
"teller"=> $gadaiData['teller'], "teller"=> $gadaiData['teller'],
"onepercent"=> $gadaiData['onepercent'], "onepercent"=> $gadaiData['onepercent'],
"ujrah"=> $gadaiData['ujrah'] "ujrah"=> $gadaiData['ujrah'],
"kadarrebet"=> $gadaiData['kadarrebet'],
"diskaun"=> $gadaiData['diskaun']
]); ]);
} }
} }
@@ -587,44 +591,80 @@ class GadaiController extends Controller
public function getLaporanGadaiRangeDate($kodcaw,Request $request){ public function getLaporanGadaiRangeDate($kodcaw,Request $request){
$cawangan = Cawangan::on('mysql7')->where('kodcaw','=',$kodcaw)->first(); $mula = $request->mula;
$akhir = $request->akhir;
$gadai_data = Gadai::on($cawangan['mysql'])->select('t_gadai','norujukan','nokp','semakbarcode','masa','berat','nilaimarhun','pinjaman','upah12','percentpinj','teller','nokp','ujrah','onepercent','tagbaru') $cawangan = Cawangan::on('mysql7')->where('kodcaw', $kodcaw)->first();
->where('t_gadai','>=',$request->mula)
->where('t_gadai','<=',$request->akhir)
->orderBy('t_gadai')
->orderBy('teller')
->orderBy('sirig')
->get();
$gadai = []; $gadai_data = Gadai::on($cawangan['mysql'])
->whereBetween('t_gadai', [$request->mula, $request->akhir])
->orderBy('t_gadai')
->orderBy('teller')
->orderBy('sirig')
->get();
if($gadai_data){ $nokps = $gadai_data->pluck('nokp')->unique();
foreach($gadai_data as $index=>$gadaiData){
$customer_info = Customer::on('mysql7')->where('kplama','=',$gadaiData['nokp'])->orWhere('kpbaru','=',$gadaiData['nokp'])->first();
array_push($gadai,[
"t_gadai"=> $gadaiData['t_gadai'],
"norujukan"=> $gadaiData['norujukan'],
"nama"=> $customer_info['nama'],
"nokp"=> $gadaiData['nokp'],
"semakbarcode"=> $gadaiData['semakbarcode'],
"masa"=> $gadaiData['masa'],
"berat"=> $gadaiData['berat'],
"nilaimarhun"=> $gadaiData['nilaimarhun'],
"pinjaman"=> $gadaiData['pinjaman'],
"upah12"=> $gadaiData['upah12'],
"percentpinj"=> $gadaiData['percentpinj'],
"alamat1"=> $customer_info['alamat1'],
"teller"=> $gadaiData['teller'],
"ujrah"=> $gadaiData['ujrah'],
"onepercent"=> $gadaiData['onepercent'],
"tagbaru"=> $gadaiData['tagbaru']
]); $customers = Customer::on('mysql7')
->where(function($query) use ($nokps) {
$query->whereIn('kpbaru', $nokps)
->orWhereIn('kplama', $nokps);
})
->get()
->flatMap(fn($c) => [
$c->kpbaru => $c,
$c->kplama => $c
]);
$gadai = $gadai_data->map(function ($g) use ($customers) {
foreach($customers as $key=>$value){
if($g->nokp == $value->kpbaru || $g->nokp == $value->kplama){
$customer = $value;
}
} }
}
return response()->json($gadai); return [
"nama" => optional($customer)->nama,
"alamat1" => optional($customer)->alamat1,
"t_gadai" => $g->t_gadai,
"norujukan" => $g->norujukan,
"cara_terima" => strtoupper((string) ($g->cara_terima ?: 'TUNAI')),
"nokp"=> $g->nokp,
"semakbarcode"=> $g->semakbarcode,
"masa"=> $g->masa,
"berat"=> $g->berat,
"nilaimarhun"=> $g->nilaimarhun,
"pinjaman"=> $g->pinjaman,
"upah12"=> $g->upah12,
"percentpinj"=> $g->percentpinj,
"alamat1"=> optional($customer)->alamat1,
"teller"=> $g->teller,
"ujrah"=> $g->ujrah,
"onepercent"=> $g->onepercent,
"kadarrebet"=> $g->kadarrebet,
"diskaun"=> $g->diskaun,
"tagbaru"=> $g->tagbaru,
"kodkerja"=> optional($customer)->kodkerja,
"bangsa"=> optional($customer)->bangsa,
];
});
// dd($gadai);
$statistikService = new StatistikService($kodcaw,$mula,$akhir);
$reportgadai = $statistikService->LaporanStatistik($gadai);
// dd($nokps);
return response()->json([
'gadai' => $gadai,
'kodcaw' => $kodcaw,
'mula' => $mula,
'akhir' => $akhir,
'statistik' => $reportgadai,
'jumlah' => $gadai->count(),
]);
} }
public function getLaporanBatalGadai($kodcaw,$tarikh){ public function getLaporanBatalGadai($kodcaw,$tarikh){
@@ -3871,11 +3911,13 @@ class GadaiController extends Controller
public function updateTagLelong(Request $request){ public function updateTagLelong(Request $request){
$norujukan = $request->norujukan; $norujukan = $request->norujukan;
$kodcaw = $request->kodcaw; $kodcaw = $request->kodcaw;
$t_lelong = $request->t_lelong;
$cawangan = Cawangan::on('mysql7')->where('kodcaw',$request->kodcaw)->first(); $cawangan = Cawangan::on('mysql7')->where('kodcaw',$request->kodcaw)->first();
$updateTag = Gadai::on($cawangan->mysql)->where('norujukan',$norujukan)->update([ $updateTag = Gadai::on($cawangan->mysql)->where('norujukan',$norujukan)->update([
'taglel'=>1 'taglel'=>1,
't_lelong' => $t_lelong,
]); ]);
return response()->json('success'); return response()->json('success');
@@ -3888,7 +3930,8 @@ class GadaiController extends Controller
$cawangan = Cawangan::on('mysql7')->where('kodcaw',$request->kodcaw)->first(); $cawangan = Cawangan::on('mysql7')->where('kodcaw',$request->kodcaw)->first();
$updateTag = Gadai::on($cawangan->mysql)->where('norujukan',$norujukan)->update([ $updateTag = Gadai::on($cawangan->mysql)->where('norujukan',$norujukan)->update([
'taglel'=>0 'taglel'=>0,
't_lelong' => null,
]); ]);
return response()->json('success'); return response()->json('success');
+164 -20
View File
@@ -8,6 +8,7 @@ use App\Cawangan;
use App\Mohonid; use App\Mohonid;
use App\MohonAnggota; use App\MohonAnggota;
use App\Customer; use App\Customer;
use App\Services\StaffNotificationClient;
use Carbon\Carbon; use Carbon\Carbon;
@@ -98,6 +99,7 @@ class KelulusanController extends Controller
{ {
$harini = Carbon::now(); $harini = Carbon::now();
$harini = new Carbon; $harini = new Carbon;
$kelulusan = null;
$cawangan = Cawangan::on('mysql7')->where('kodcaw','=',$kodcaw)->first(); $cawangan = Cawangan::on('mysql7')->where('kodcaw','=',$kodcaw)->first();
$pengesahan = $request->pengesahan; $pengesahan = $request->pengesahan;
@@ -195,7 +197,33 @@ class KelulusanController extends Controller
$audit = new Audit(); $audit = new Audit();
$audit->users = (isset($request->namakhazanah) ? $request->namakhazanah : ''); $audit->users = (isset($request->namakhazanah) ? $request->namakhazanah : '');
$audit->actions = "Pengesahan Kelulusan 75%"; $audit->actions = $request->actions ?? "pengesahan kelulusan 75%";
// Only prepare detailed audit data for Pampasan approval
if($request->actions == 'Pengesahan Pembayaran Pampasan') {
// Prepare data for audit - ensure it's an array
$auditData = [];
// If kelulusan is a scalar (update result), create array structure
if (is_scalar($kelulusan) || is_null($kelulusan)) {
$auditData = ['update_result' => $kelulusan];
} else {
$auditData = $kelulusan;
}
// Add namapelulus and norujukanasal to the audit data
if(isset($request->namaoperasi)) {
$auditData['namapelulus'] = !empty($request->namaoperasi) ? $request->namaoperasi : null;
}
if(isset($request->norujukan)) {
$auditData['norujukan'] = !empty($request->norujukan) ? $request->norujukan : null;
}
} else {
// For other actions, use simple kelulusan data
$auditData = $kelulusan;
}
$audit->new_data = json_encode($auditData);
$audit->kodcaw = $kodcaw; $audit->kodcaw = $kodcaw;
$audit->created_at = $harini; $audit->created_at = $harini;
$audit->updated_at = $harini; $audit->updated_at = $harini;
@@ -323,9 +351,7 @@ public function create(REQUEST $request,$kodcaw,$norujukan,$roles)
if($roles == "khazanah") if($roles == "khazanah")
{ {
$kelulusan=Mohon::on($cawangan['mysql']) $createData = [
->create([
'tarikh'=> $harini->toDateString(), 'tarikh'=> $harini->toDateString(),
'norujukan'=> $norujukan, 'norujukan'=> $norujukan,
'siri' => $request->siri, 'siri' => $request->siri,
@@ -339,10 +365,14 @@ public function create(REQUEST $request,$kodcaw,$norujukan,$roles)
'jenistebus' => $request->jenistebus, 'jenistebus' => $request->jenistebus,
'teller' => $request->teller, 'teller' => $request->teller,
'pelulus' => ($request->pelulus) ? $request->pelulus : '' 'pelulus' => ($request->pelulus) ? $request->pelulus : ''
];
// Add peloperasi if status is Kelulusan Pengeluaran Pampasan
if($request->status == 'Kelulusan Pengeluaran Pampasan' && isset($request->peloperasi)) {
$createData['peloperasi'] = $request->peloperasi;
}
$kelulusan=Mohon::on($cawangan['mysql'])->create($createData);
]);
} }
else if($roles == "operasi") else if($roles == "operasi")
{ {
@@ -369,7 +399,7 @@ public function create(REQUEST $request,$kodcaw,$norujukan,$roles)
$audit = new Audit(); $audit = new Audit();
$audit->users = (isset($request->teller) ? $request->teller : ''); $audit->users = (isset($request->teller) ? $request->teller : '');
$audit->actions = "Minta Pengesahan kelulusan 75%"; $audit->actions = $request->actions ?? "Minta Pengesahan kelulusan 75%";
$audit->new_data = json_encode($kelulusan); $audit->new_data = json_encode($kelulusan);
$audit->kodcaw = $kodcaw; $audit->kodcaw = $kodcaw;
$audit->created_at = $harini; $audit->created_at = $harini;
@@ -415,6 +445,8 @@ public function create(REQUEST $request,$kodcaw,$norujukan,$roles)
$audit->updated_at = $harini; $audit->updated_at = $harini;
$audit->save(); $audit->save();
$this->notifyOperasiAssignAnggota($kodcaw, $cawangan, $kelulusan, $request);
// ✅ Return JSON response ke frontend // ✅ Return JSON response ke frontend
return response()->json([ return response()->json([
'success' => true, 'success' => true,
@@ -437,6 +469,58 @@ public function create(REQUEST $request,$kodcaw,$norujukan,$roles)
} }
} }
/**
* Inbox for all operasi staff. Failures must not block the teller request.
*
* @param string $kodcaw
* @param \App\Cawangan $cawangan
* @param \App\MohonAnggota $kelulusan
* @param \Illuminate\Http\Request $request
* @return void
*/
protected function notifyOperasiAssignAnggota($kodcaw, $cawangan, $kelulusan, Request $request)
{
try {
$nama = trim((string) ($request->nama ?? ''));
if ($nama === '' && !empty($kelulusan->nokp)) {
$customer = Customer::on('mysql7')
->where('kpbaru', $kelulusan->nokp)
->orWhere('kplama', $kelulusan->nokp)
->first();
if ($customer && !empty($customer->nama)) {
$nama = trim((string) $customer->nama);
}
}
$namaCaw = $kodcaw;
if ($cawangan) {
$resolved = trim((string) $cawangan->nama_cawangan);
if ($resolved !== '') {
$namaCaw = $resolved;
}
}
app(StaffNotificationClient::class)->notify([
'type' => 'anggota.pending_operasi',
'cawangan' => $kodcaw,
'audience' => ['role' => 'operasi'],
'data' => [
'id' => $kelulusan->id,
'nokp' => $kelulusan->nokp,
'nama' => $nama,
'teller' => $kelulusan->teller,
'komen' => $kelulusan->komen,
'cawangan_nama' => $namaCaw,
],
]);
} catch (\Throwable $e) {
Log::warning('Assign anggota operasi notification failed: '.$e->getMessage(), [
'kodcaw' => $kodcaw,
'nokp' => isset($kelulusan->nokp) ? $kelulusan->nokp : null,
]);
}
}
//KEPOHONAN EDIT DAN HAPUS //KEPOHONAN EDIT DAN HAPUS
public function kepohonancreate(REQUEST $request,$kodcaw,$norujukan) public function kepohonancreate(REQUEST $request,$kodcaw,$norujukan)
@@ -571,26 +655,86 @@ public function create(REQUEST $request,$kodcaw,$norujukan,$roles)
return response()->json($arraykelulusan,200); return response()->json($arraykelulusan,200);
} }
public function listoperasikelulusan() public function listoperasikelulusan(Request $request)
{ {
$harini = Carbon::now(); $dateFrom = $request->query('date_from');
$harini = new Carbon; $dateTo = $request->query('date_to');
$search = trim((string) $request->query('search', ''));
// Default to last 30 days to avoid loading entire history
if (!$dateFrom && !$dateTo) {
$dateTo = Carbon::now()->toDateString();
$dateFrom = Carbon::now()->subDays(30)->toDateString();
}
$cawangan_all = Cawangan::on('mysql7')
->select('mysql', 'details_caw', 'kodcaw')
->get();
$cawangan_all = Cawangan::on('mysql7')->get();
$arraykelulusan = []; $arraykelulusan = [];
foreach($cawangan_all as $index=>$cawangan){ foreach ($cawangan_all as $cawangan) {
$kelulusan=Mohon::on($cawangan['mysql']) $query = Mohon::on($cawangan['mysql'])
->where('peloperasi','=','operasi') ->select([
->where('operasi','!=','') 'tarikh',
->get(); 'norujukan',
'komen',
'jumpinj',
'nilaimarhun',
'berat',
'margin',
'status',
'operasi',
'masalulus',
])
->where('peloperasi', '=', 'operasi')
->where('operasi', '!=', '');
if(sizeof($kelulusan) != 0){ if ($dateFrom) {
array_push($arraykelulusan,["kelulusanall" => $kelulusan,"cawangan" => $cawangan['details_caw'],"cawangankod" => $cawangan['kodcaw']]); $query->where('tarikh', '>=', $dateFrom);
}
if ($dateTo) {
$query->where('tarikh', '<=', $dateTo);
}
if ($search !== '') {
$query->where(function ($q) use ($search) {
$q->where('norujukan', 'like', "%{$search}%")
->orWhere('operasi', 'like', "%{$search}%")
->orWhere('status', 'like', "%{$search}%")
->orWhere('komen', 'like', "%{$search}%");
});
} }
}
return response()->json($arraykelulusan,200); $kelulusan = $query->orderBy('tarikh', 'desc')->get();
foreach ($kelulusan as $kel) {
$komenParts = explode('|', (string) ($kel->komen ?? ''));
$komenParts = array_values(array_filter($komenParts, function ($part) {
return $part !== '';
}));
$arraykelulusan[] = [
'tarikh' => $kel->tarikh ?? '-',
'norujukan' => $kel->norujukan ?? '-',
'status' => $kel->status ?? '-',
'komen' => $komenParts[0] ?? ($kel->komen ?: '-'),
'pinjaman' => $kel->jumpinj ?? '-',
'nilaimarhun' => $komenParts[1] ?? ($kel->nilaimarhun ?? '-'),
'berat' => $komenParts[2] ?? ($kel->berat ?? '-'),
'margin' => $komenParts[3] ?? ($kel->margin ?? '-'),
'pelulus' => $kel->operasi ?? '-',
'masalulus' => $kel->masalulus ?? '-',
'cawangan' => $cawangan['details_caw'],
'cawangankod' => $cawangan['kodcaw'],
];
}
}
usort($arraykelulusan, function ($a, $b) {
return strcmp((string) ($b['tarikh'] ?? ''), (string) ($a['tarikh'] ?? ''));
});
return response()->json($arraykelulusan, 200);
} }
public function UpdateHapusAnsuranOperasi(Request $request){ public function UpdateHapusAnsuranOperasi(Request $request){
+5 -2
View File
@@ -145,15 +145,18 @@ class KomuditiController extends Controller
$komuditi_current = KomuditiPurchase::on('mysql7')->where('date_purchase','=',$current->toDateString())->orderBy('created_at','desc')->first(); $komuditi_current = KomuditiPurchase::on('mysql7')->where('date_purchase','=',$current->toDateString())->orderBy('created_at','desc')->first();
$unit_current = $komuditi_current['unit_komuditi']; $unit_current = $komuditi_current['unit_komuditi'];
$update_unit = $unit_current - $request->unit_komuditi; $update_unit = $unit_current - $request->unit_komuditi;
$unit_current = round((float) $komuditi_current['unit_komuditi'], 2);
$unit_komuditi = round((float) $request->unit_komuditi, 2);
$update_unit = round($unit_current - $unit_komuditi, 2);
$update_komuditi = KomuditiPurchase::on('mysql7')->where('id','=',$komuditi_current['id'])->update([ $update_komuditi = KomuditiPurchase::on('mysql7')->where('id','=',$komuditi_current['id'])->update([
'unit_komuditi' => $update_unit 'unit_komuditi' => $update_unit
]); ]);
$komuditi_transaksi = KomuditiTransaksi::on('mysql7')->create([ $komuditi_transaksi = KomuditiTransaksi::on('mysql7')->create([
'unit_komuditi' => $request->unit_komuditi, 'unit_komuditi' => $unit_komuditi,
'nosijil'=>$komuditi_current['no_sijil'], 'nosijil'=>$komuditi_current['no_sijil'],
'norujukan' => $request->norujukan, 'norujukan' => $request->norujukan,
'kodcaw' => $request->kodcaw , 'kodcaw' => $request->kodcaw ,
+1 -1
View File
@@ -847,7 +847,7 @@ $date = new Carbon($request->tarikh);
$bilangan_tebus = $tebus->count(); $bilangan_tebus = $tebus->count();
// $bilangan_ansuran = $ansuran->count(); // $bilangan_ansuran = $ansuran->count();
//$bilangan_customer_baru = Customer::on($cawangan['mysql'])->where([['tarikhdaftar','>=',$request->mula],['tarikhdaftar','<=',$request->akhir]])->count(); //$bilangan_customer_baru = Customer::on($cawangan['mysql'])->where([['tarikhdaftar','>=',$request->mula],['tarikhdaftar','<=',$request->akhir]])->count();
$bilangan_customer_baru = Customer::on('mysql7')->where([['tarikhdaftar','>=',$request->mula],['tarikhdaftar','<=',$request->akhir]])->count(); $bilangan_customer_baru = Customer::on('mysql7')->whereBetween('tarikhdaftar', [$request->mula, $request->akhir])->where('kodcaw', $request->kodcaw)->count();
//f //f
$data_lelong = Lelong::on($cawangan['mysql'])->where([['t_jual','>=',$request->mula],['t_jual','<=',$request->akhir]])->get(); $data_lelong = Lelong::on($cawangan['mysql'])->where([['t_jual','>=',$request->mula],['t_jual','<=',$request->akhir]])->get();
+294 -163
View File
@@ -11,6 +11,7 @@ use App\Negeri;
use App\Lelong; use App\Lelong;
use App\Transaction; use App\Transaction;
use App\Cawangan; use App\Cawangan;
use App\Feature;
use App\Gadai; use App\Gadai;
use App\TuntutBaki; use App\TuntutBaki;
use App\WTD; use App\WTD;
@@ -26,6 +27,7 @@ use App\Tunai;
use App\Audit; use App\Audit;
use App\GlDetail; use App\GlDetail;
use App\Pembeli; use App\Pembeli;
use Illuminate\Http\Client\ConnectionException;
use Illuminate\Http\Request; use Illuminate\Http\Request;
use Illuminate\Support\Facades\Http; use Illuminate\Support\Facades\Http;
use App\Services\RingkasanHarianServices; use App\Services\RingkasanHarianServices;
@@ -604,16 +606,7 @@ class LelongController extends Controller
$cawangan = Cawangan::on('mysql7')->where('kodcaw','=',$request->kodcaw)->first(); $cawangan = Cawangan::on('mysql7')->where('kodcaw','=',$request->kodcaw)->first();
if($cawangan['tagarrahnbid'] == 1){ if($cawangan['tagarrahnbid'] == 1){
if(env('APP_ENV') != 'production'){ $lelong = $this->fetchPortalLelong($request->kodcaw, $request->norujukan);
$link = 'http://niklah.arrahn.com.my/api/portalApi';
}else{
$link = 'https://adminbid-kopkb.erahn.com.my/api/portalApi';
}
$lelong = Http::withOptions(['verify' => true])->get($link,[
'norujukan' => $request->norujukan
])->json();
$lelong = ($lelong != null) ? $lelong['lelong'] : [];
if( $lelong == null ) if( $lelong == null )
{ {
$lelong = Lelong::on($cawangan['mysql']) $lelong = Lelong::on($cawangan['mysql'])
@@ -656,10 +649,7 @@ class LelongController extends Controller
$cawangan = Cawangan::on('mysql7')->where('kodcaw', '=', $request->kodcaw)->first(); $cawangan = Cawangan::on('mysql7')->where('kodcaw', '=', $request->kodcaw)->first();
if ($cawangan['tagarrahnbid'] == 0){ if ($cawangan['tagarrahnbid'] == 0){
$lelong = Http::withOptions(['verify' => true])->get(config('app_parameter.api_arrahnbid').'portalApi',[ $lelong = $this->fetchPortalLelong($request->kodcaw, $request->norujukan);
'norujukan' => $request->norujukan
])->json();
$lelong = ($lelong != null) ? $lelong['lelong'] : [];
if( $lelong == null ) if( $lelong == null )
{ {
$lelong = Lelong::on($cawangan['mysql']) $lelong = Lelong::on($cawangan['mysql'])
@@ -729,8 +719,8 @@ class LelongController extends Controller
if($cawangan['tagarrahnbid'] == 1) if($cawangan['tagarrahnbid'] == 1)
{ {
$lelong = Http::withOptions(['verify' => true])->get(config('app_parameter.api_arrahnbid').'portalApi',['norujukan' => $request->norujukan])->json(); $lelong = $this->fetchPortalLelong($request->kodcaw, $request->norujukan);
$lelong = ($lelong != null) ? $lelong['lelong'] : []; $lelong = ($lelong != null) ? $lelong : [];
}else{ }else{
$lelong = Lelong::on($cawangan['mysql'])->where([['norujukan',$request->norujukan]])->first(); $lelong = Lelong::on($cawangan['mysql'])->where([['norujukan',$request->norujukan]])->first();
} }
@@ -1069,44 +1059,79 @@ class LelongController extends Controller
public function exportLelong(Request $request) public function exportLelong(Request $request)
{ {
$currentDate = Carbon::now(); $currentDate = Carbon::now()->toDateString();
$currentDate = $currentDate->toDateString();
$cawangan = Cawangan::on('mysql7')->where('kodcaw', $request->kodcaw)->first(); // --- Step 0: Dapatkan Cawangan ---
$cawangan = Cawangan::on('mysql7')
->where('kodcaw', $request->kodcaw)
->first();
$batchlel = BatchLel::on($cawangan['mysql']) if (!$cawangan) {
->select('batchno') Log::error("Export Lelong gagal: cawangan tidak ditemui", ['kodcaw' => $request->kodcaw]);
->orderBy('batchno', 'desc') return response()->json(['error' => 'Cawangan tidak ditemui'], 404);
->first(); }
$newBatchNo = $batchlel->batchno + 1; Log::info("Mula Export Lelong", [
'kodcaw' => $cawangan->kodcaw,
$newBatchLel = BatchLel::on($cawangan['mysql'])->create([ 'nama_cawangan' => $cawangan->details_caw,
'kodcaw' => $request->kodcaw,
'batchno' => $newBatchNo,
'tarikh' => $request->tarikh,
'tarikh2' => $request->tarikh,
't_daftar' => $currentDate,
'masadari' => $request->masadari,
'masahingga' => $request->masahingga
]); ]);
$lelong = Lelong::on($cawangan['mysql']) // --- Step 1: Batch (Cegah duplicate) ---
->select('sirilel') $batchlel = BatchLel::on($cawangan['mysql'])
->orderBy('batchno', 'desc') ->where('kodcaw', $request->kodcaw)
->first(); ->whereDate('tarikh', $request->tarikh)
->where('masadari', $request->masadari)
->where('masahingga', $request->masahingga)
->first();
if (!$batchlel) {
$lastBatchNo = BatchLel::on($cawangan['mysql'])->max('batchno') ?? 0;
$newBatchNo = $lastBatchNo + 1;
$batchlel = BatchLel::on($cawangan['mysql'])->create([
'kodcaw' => $request->kodcaw,
'batchno' => $newBatchNo,
'tarikh' => $request->tarikh,
'tarikh2' => $request->tarikh,
't_daftar' => $currentDate,
'masadari' => $request->masadari,
'masahingga' => $request->masahingga
]);
Log::info("Batch baru dicipta", ['batchno' => $newBatchNo]);
} else {
$newBatchNo = $batchlel->batchno;
Log::info("Batch sedia ada digunakan", ['batchno' => $newBatchNo]);
}
// --- Step 2: Siri Lelong Terakhir ---
$lastSiriLelong = Lelong::on($cawangan['mysql'])->max('sirilel') ?? 0;
$lelong_arr = [];
// --- Step 3: Cegah duplicate Lelong ---
$existingNorujukan = Lelong::on($cawangan['mysql'])
->whereIn('norujukan', collect($request->lelongbid)->pluck('norujukan'))
->pluck('norujukan')
->toArray();
foreach ($request->lelongbid as $index) { foreach ($request->lelongbid as $index) {
if (in_array($index['norujukan'], $existingNorujukan)) {
Log::warning("Skip Lelong duplicate", ['norujukan' => $index['norujukan']]);
continue;
}
$no_pembeli = Pembeli::on($cawangan['mysql'])->where('nokp', '=', $index['user_details']['nokp'])->select('nopembeli')->first(); // --- Step 4: Semak / cipta pembeli ---
if ($no_pembeli) { $no_pembeli = Pembeli::on($cawangan['mysql'])
$no_pembeli_data = $no_pembeli->nopembeli; ->where('nokp', $index['user_details']['nokp'])
} else { ->value('nopembeli');
$last_no_pembeli = Pembeli::on($cawangan['mysql'])->select('nopembeli')->orderBy('nopembeli', 'desc')->first();
$no_pembeli_data = $last_no_pembeli->nopembeli + 1;
$newPembeli = Pembeli::on($cawangan['mysql'])->create([ if (!$no_pembeli) {
'nopembeli' => $no_pembeli_data, $last_no_pembeli = Pembeli::on($cawangan['mysql'])
->max('nopembeli') ?? 0;
$no_pembeli = $last_no_pembeli + 1;
Pembeli::on($cawangan['mysql'])->create([
'nopembeli' => $no_pembeli,
'nokp' => $index['user_details']['nokp'], 'nokp' => $index['user_details']['nokp'],
'nama' => $index['user_details']['name'], 'nama' => $index['user_details']['name'],
'alamat1' => $index['user_details']['alamat'], 'alamat1' => $index['user_details']['alamat'],
@@ -1114,105 +1139,147 @@ class LelongController extends Controller
]); ]);
} }
$update_gadai = Gadai::on($cawangan['mysql'])->where('norujukan','=',$index['norujukan'])->update(array( // --- Step 5: Update gadai ---
'sttebus' => "L", Gadai::on($cawangan['mysql'])
't_update' => $request->tarikh ->where('norujukan', $index['norujukan'])
)); ->update([
'sttebus' => "L",
't_update' => $request->tarikh
]);
$lelong_to_be_inserted = new Lelong(); // --- Step 6: Simpan data Lelong ---
$lelong_to_be_inserted->batchno = $newBatchNo; $lelong_arr[] = [
$lelong_to_be_inserted->sirilel = $lelong->sirilel + 1; 'batchno' => $newBatchNo,
$lelong_to_be_inserted->kodcaw = $index['kodcaw']; 'sirilel' => ++$lastSiriLelong,
$lelong_to_be_inserted->norujukan = $index['norujukan']; 'kodcaw' => $index['kodcaw'],
$lelong_to_be_inserted->t_lelong = $request->tarikh; 'norujukan' => $index['norujukan'],
$lelong_to_be_inserted->hargaasas = $index['hargaasas']; 't_lelong' => $request->tarikh,
$lelong_to_be_inserted->hargajual = $index['hargajual']; 'hargaasas' => $index['hargaasas'],
$lelong_to_be_inserted->glcode = "1000/010"; 'hargajual' => $index['hargajual'],
$lelong_to_be_inserted->t_jual = $index['t_jual']; 'glcode' => "1000/010",
$lelong_to_be_inserted->nopembeli = $no_pembeli_data; 't_jual' => $index['t_jual'],
$lelong_to_be_inserted->jbg = $index['jbg']; 'nopembeli' => $no_pembeli,
$lelong_to_be_inserted->kadarupah = $index['kadarupah']; 'jbg' => $index['jbg'],
$lelong_to_be_inserted->upahsimpan = $index['upahsimpan']; 'kadarupah' => $index['kadarupah'],
$lelong_to_be_inserted->ansuran = $index['ansuran']; 'upahsimpan' => $index['upahsimpan'],
$lelong_to_be_inserted->nilaimarhun = $index['nilaimarhun']; 'ansuran' => $index['ansuran'],
$lelong_to_be_inserted->nilaimarhuns = $index['nmarhuns']; 'nilaimarhun' => $index['nilaimarhun'],
$lelong_to_be_inserted->pinjaman = $index['pinjaman']; 'nilaimarhuns' => $index['nmarhuns'],
$lelong_to_be_inserted->bakiupah = $index['bakiupah']; 'pinjaman' => $index['pinjaman'],
$lelong_to_be_inserted->cajlelong = $index['cajlelong']; 'bakiupah' => $index['bakiupah'],
$lelong_to_be_inserted->baki = $index['baki']; 'cajlelong' => $index['cajlelong'],
$lelong_to_be_inserted->teller = $index['teller']; 'baki' => $index['baki'],
$lelong_to_be_inserted->prkod = "01"; 'teller' => $index['teller'],
$lelong_to_be_inserted->kodgl = "1000/013"; 'prkod' => "01",
$lelong_to_be_inserted->berat = $index['berat']; 'kodgl' => "1000/013",
$lelong_to_be_inserted->marhun = $index['marhun']; 'berat' => $index['berat'],
$lelong_to_be_inserted->fasa = $index['fasa']; 'marhun' => $index['marhun'],
$lelong_to_be_inserted->ujrah = $index['ujrah']; 'fasa' => $index['fasa'],
$lelong_to_be_inserted->onepercent = $index['onepercent']; 'ujrah' => $index['ujrah'],
$lelong_to_be_inserted->tagujrah = $index['tagujrah']; 'onepercent' => $index['onepercent'],
'tagujrah' => $index['tagujrah'],
$lelong_arr[] = $lelong_to_be_inserted->attributesToArray(); ];
} }
Lelong::on($cawangan['mysql'])->insert($lelong_arr); if ($lelong_arr) {
Lelong::on($cawangan['mysql'])->insert($lelong_arr);
foreach ($request->lelongbidmarhun as $data) { Log::info("Berjaya simpan lelong baru", ['total' => count($lelong_arr)]);
$lelmarhun_to_be_inserted = new LelMarhun();
$lelmarhun_to_be_inserted->kodcaw = $request->kodcaw;
$lelmarhun_to_be_inserted->norujukan = $data['norujukan'];
$lelmarhun_to_be_inserted->bil = $data['bil'];
$lelmarhun_to_be_inserted->marhun = $data['marhun'];
$lelmarhun_to_be_inserted->nota = $data['nota'];
$lelmarhun_to_be_inserted->karat = $data['karat'];
$lelmarhun_to_be_inserted->berat = $data['berat'];
$lelmarhun_to_be_inserted->harga = $data['harga'];
$lelmarhun_to_be_inserted->n_marhun = $data['n_marhun'];
$lelmarhun_to_be_inserted->hargaasas = $data['hargaasas'];
$lelmarhun_to_be_inserted->batch_no = $newBatchNo;
// $lelmarhun_to_be_inserted->beratasal = $;
$lelmarhun_arr[] = $lelmarhun_to_be_inserted->attributesToArray();
} }
LelMarhun::on($cawangan['mysql'])->insert($lelmarhun_arr); // --- Step 7: LELMARHUN (cegah duplicate) ---
if ($request->lelongbidmarhun) {
$existingMarhun = LelMarhun::on($cawangan['mysql'])
->whereIn('norujukan', collect($request->lelongbidmarhun)->pluck('norujukan'))
->pluck('norujukan')
->toArray();
if ($request->tunai != null) { $lelmarhun_arr = collect($request->lelongbidmarhun)
$tunai = Tunai::on($cawangan['mysql'])->create([ ->reject(fn($data) => in_array($data['norujukan'], $existingMarhun))
'tarikh' => $request->tarikh, ->map(function ($data) use ($request, $newBatchNo) {
'kodcaw' => $request->kodcaw, return [
'kodlaluan' => "LELONG", 'kodcaw' => $request->kodcaw,
'masuk' => $request->tunai, 'norujukan' => $data['norujukan'],
'baki' => $request->tunai, 'bil' => $data['bil'],
]); 'marhun' => $data['marhun'],
'nota' => $data['nota'],
'karat' => $data['karat'],
'berat' => $data['berat'],
'harga' => $data['harga'],
'n_marhun' => $data['n_marhun'],
'hargaasas' => $data['hargaasas'],
'batch_no' => $newBatchNo
];
})
->toArray();
if ($lelmarhun_arr) {
LelMarhun::on($cawangan['mysql'])->insert($lelmarhun_arr);
Log::info("LelMarhun baru disimpan", ['total' => count($lelmarhun_arr)]);
}
} }
if ($request->gldetail != null) { // --- Step 8: GL dan Tunai (check duplicate descpt) ---
$gldetail = GlDetail::on($cawangan['mysql'])->create([ if ($request->tunai > 0) {
'kodcaw' => $request->kodcaw, $existsTunai = Tunai::on($cawangan['mysql'])
'tarikh' => $request->tarikh, ->where('kodcaw', $request->kodcaw)
'dtacct' => "1000/010", ->where('tarikh', $request->tarikh)
'ktacct' => "1000/020", ->where('kodlaluan', 'LELONG')
'descpt' => "SERAHAN LELONG ONLINE, " . $request->tarikh, ->exists();
'amaun' => $request->gldetail,
'teller' => "LELONG ONLINE", if (!$existsTunai) {
'serahan' => $request->gldetail, Tunai::on($cawangan['mysql'])->create([
]); 'tarikh' => $request->tarikh,
'kodcaw' => $request->kodcaw,
'kodlaluan' => "LELONG",
'masuk' => $request->tunai,
'baki' => $request->tunai,
]);
Log::info("Rekod Tunai lelong dimasukkan");
} else {
Log::warning("Skip Tunai duplicate");
}
} }
if ($request->gldetailcdm != null) { $glDescs = [
GlDetail::on($cawangan['mysql'])->create([ 'SERAHAN LELONG ONLINE' => $request->gldetail,
'kodcaw' => $request->kodcaw, 'SERAHAN LELONG CDM' => $request->gldetailcdm,
'tarikh' => $request->tarikh, ];
'dtacct' => "1000/010",
'ktacct' => "1000/020", foreach ($glDescs as $desc => $amount) {
'descpt' => "SERAHAN LELONG CDM, " . $request->tarikh, if ($amount > 0) {
'amaun' => $request->gldetailcdm, $existsGl = GlDetail::on($cawangan['mysql'])
'teller' => "LELONG ONLINE", ->where('kodcaw', $request->kodcaw)
'serahan' => $request->gldetailcdm, ->where('tarikh', $request->tarikh)
]); ->where('descpt', 'like', "%{$desc}%")
->exists();
if (!$existsGl) {
GlDetail::on($cawangan['mysql'])->create([
'kodcaw' => $request->kodcaw,
'tarikh' => $request->tarikh,
'dtacct' => "1000/010",
'ktacct' => "1000/020",
'descpt' => "{$desc}, {$request->tarikh}",
'amaun' => $amount,
'teller' => "LELONG ONLINE",
'serahan' => $amount,
]);
Log::info("Rekod GL dimasukkan", ['desc' => $desc]);
} else {
Log::warning("Skip GL duplicate", ['desc' => $desc]);
}
}
} }
return response()->json("success"); // --- Step 9: Log Akhir ---
Log::info('Berjaya Export Cawangan:', [
'kodcaw' => $cawangan->kodcaw,
'nama_cawangan' => $cawangan->details_caw,
'batch_baru' => $newBatchNo,
'total_lelong' => count($lelong_arr),
]);
return response()->json(['status' => 'success']);
} }
public function getRingkasanHarian(Request $request){ public function getRingkasanHarian(Request $request){
@@ -1318,42 +1385,53 @@ class LelongController extends Controller
public function showAllLelongByCawanganBatchno($kodcaw) public function showAllLelongByCawanganBatchno($kodcaw)
{ {
$item = array('PMT','batu','permata'); $item = ['PMT', 'batu', 'permata'];
$cawangan = Cawangan::on('mysql7')->where('kodcaw','=',$kodcaw)->first();
// Semak kewujudan cawangan dulu
$cawangan = Cawangan::on('mysql7')->where('kodcaw', $kodcaw)->first();
if (!$cawangan) {
return response()->json(['error' => 'Cawangan tidak dijumpai.'], 404);
}
// Ambil data lelong
$lelong_data = Lelong::on($cawangan['mysql']) $lelong_data = Lelong::on($cawangan['mysql'])
->leftJoin('gadai', 'gadai.norujukan', '=', 'lelong.norujukan') ->leftJoin('gadai', 'gadai.norujukan', '=', 'lelong.norujukan')
->join('lelmarhun', 'lelmarhun.norujukan', '=', 'lelong.norujukan') ->join('lelmarhun', 'lelmarhun.norujukan', '=', 'lelong.norujukan')
->whereNull('upah12') ->whereNull('upah12')
// ->where('lelong.marhun', 'like', '%PMT%') ->where(function ($query) use ($item) {
// ->orWhere('lelong.marhun', 'like', '%batu%') foreach ($item as $i) {
// ->orWhere('lelong.marhun', 'like', '%permata%') $query->orWhere('lelmarhun.nota', 'like', '%' . $i . '%');
->Where(function ($query) use($item) { }
for ($i = 0; $i < count($item); $i++){ })
$query->orwhere('lelmarhun.nota', 'like', '%' . $item[$i] .'%'); ->orderBy('lelong.t_lelong', 'asc')
} ->select(
}) 'lelong.t_lelong',
->orderBy('lelong.t_lelong','asc') 'gadai.t_gadai',
->select('lelong.t_lelong','gadai.t_gadai','gadai.nokp','lelong.pinjaman','lelong.baki','lelong.batchno','lelong.norujukan') 'gadai.nokp',
->whereNull('upah12') 'lelong.pinjaman',
->distinct() 'lelong.baki',
->get(); 'lelong.batchno',
// dd($lelong_data); 'lelong.norujukan'
)
->distinct()
->get();
// Group by batch number
$groupbybatch = $lelong_data->groupBy('batchno'); $groupbybatch = $lelong_data->groupBy('batchno');
$lelong = []; $lelong = [];
foreach($groupbybatch as $index=>$lelongData){ foreach ($groupbybatch as $batchno => $lelongData) {
$total_pembiayaan = $lelongData->sum('pinjaman'); $total_pembiayaan = $lelongData->sum('pinjaman');
// dd($total_pembiayaan); $total_lelong = $lelongData->count();
$total_lelong = $lelongData->count('norujukan'); $t_lelong = optional($lelongData->first())->t_lelong; // elak error kalau kosong
array_push($lelong,[
// "upah12"=> $lelongData->upah12, $lelong[] = [
"t_lelong"=> $lelongData->groupBy('t_lelong'), 't_lelong' => $t_lelong,
"batchno"=> $index, 'batchno' => $batchno,
"total_pembiayaan"=> $total_pembiayaan, 'total_pembiayaan' => $total_pembiayaan,
"total_lelong"=> $total_lelong, 'total_lelong' => $total_lelong,
"kodcaw"=> $kodcaw, 'kodcaw' => $kodcaw,
]); ];
// dd($lelong);
} }
return response()->json($lelong); return response()->json($lelong);
} }
@@ -1895,4 +1973,57 @@ class LelongController extends Controller
return response()->json($arrayblm); return response()->json($arrayblm);
} }
public function getBakiLelongByTeller($kodcaw, Request $request)
{
$cawangan = Cawangan::on('mysql7')->where('kodcaw', $kodcaw)->first();
$date = $request->tarikh;
$rugiLelong = TuntutBaki::on($cawangan['mysql'])
->whereDate('tarikh', $date)
->where('jumlah', '<', 0)
->where('teller','=', $request->kodlaluan)
->sum('jumlah');
$bakiLelong = TuntutBaki::on($cawangan['mysql'])
->whereDate('tarikh', $date)
->where('jumlah', '>', 0)
->where('teller','=', $request->kodlaluan)
->sum('jumlah');
return response()->json([
'tarikh' => $date,
'cawangan' => $kodcaw,
'rugi_lelong' => $rugiLelong,
'baki_lelong' => $bakiLelong
], 200);
}
/**
* Fetch lelong status from arrahnbid. Returns null when the portal is
* unreachable so callers can fall back to the local lelong table.
*/
private function fetchPortalLelong($kodcaw, $norujukan)
{
try {
$payload = Http::withOptions(['verify' => true])
->timeout(5)
->get(Feature::arrahnbidUrl($kodcaw).'portalApi', [
'norujukan' => $norujukan,
])
->json();
return ($payload != null) ? ($payload['lelong'] ?? null) : null;
} catch (ConnectionException $e) {
Log::warning('Arrahnbid portal unreachable; falling back to local lelong.', [
'kodcaw' => $kodcaw,
'norujukan' => $norujukan,
'url' => Feature::arrahnbidUrl($kodcaw).'portalApi',
'error' => $e->getMessage(),
]);
return null;
}
}
} }
+8 -2
View File
@@ -203,7 +203,10 @@ class MarhunController extends Controller
$marhun = Marhun::on($cawangan['mysql']) $marhun = Marhun::on($cawangan['mysql'])
->select('marhun.norujukan','gadai.nokp','customer.nama','marhun.marhun','marhun.nota','marhun.berat','marhun.karat','marhun.harga','marhun.n_marhun','marhun.t_gadai','marhun.tag_permata', 'marhun.berat_batu_permata') ->select('marhun.norujukan','gadai.nokp','customer.nama','marhun.marhun','marhun.nota','marhun.berat','marhun.karat','marhun.harga','marhun.n_marhun','marhun.t_gadai','marhun.tag_permata', 'marhun.berat_batu_permata')
->rightJoin('gadai', 'gadai.norujukan', '=', 'marhun.norujukan') ->rightJoin('gadai', 'gadai.norujukan', '=', 'marhun.norujukan')
->rightJoin('online_arrahn.customer as customer', 'customer.kpbaru','=','gadai.nokp') ->rightJoin('master_erahn.customer as customer', function($join) {
$join->on('customer.kpbaru', '=', 'gadai.nokp')
->orOn('customer.kplama', '=', 'gadai.nokp');
})
->where('marhun.t_gadai','=',$tarikh) ->where('marhun.t_gadai','=',$tarikh)
->orderBy('marhun.t_gadai') ->orderBy('marhun.t_gadai')
->get(); ->get();
@@ -221,7 +224,10 @@ class MarhunController extends Controller
$marhun = Marhun::on($cawangan['mysql']) $marhun = Marhun::on($cawangan['mysql'])
->select('marhun.norujukan','gadai.sttebus','gadai.pinjaman','gadai.nokp','customer.nama','marhun.marhun','marhun.nota','marhun.berat','marhun.karat','marhun.harga','marhun.n_marhun','marhun.t_gadai') ->select('marhun.norujukan','gadai.sttebus','gadai.pinjaman','gadai.nokp','customer.nama','marhun.marhun','marhun.nota','marhun.berat','marhun.karat','marhun.harga','marhun.n_marhun','marhun.t_gadai')
->rightJoin('gadai', 'gadai.norujukan', '=', 'marhun.norujukan') ->rightJoin('gadai', 'gadai.norujukan', '=', 'marhun.norujukan')
->rightJoin('online_arrahn.customer as customer', 'customer.kpbaru','=','gadai.nokp') ->rightJoin('master_erahn.customer as customer', function($join) {
$join->on('customer.kpbaru', '=', 'gadai.nokp')
->orOn('customer.kplama', '=', 'gadai.nokp');
})
->where('marhun.t_gadai','<=',$tarikh) ->where('marhun.t_gadai','<=',$tarikh)
->whereYear('marhun.t_gadai','=',$current->year) ->whereYear('marhun.t_gadai','=',$current->year)
->where('gadai.sttebus','=','') ->where('gadai.sttebus','=','')
+195 -3
View File
@@ -2,14 +2,206 @@
namespace App\Http\Controllers; namespace App\Http\Controllers;
use App\Audit;
use App\MaxMutuEmas;
use App\MaxPinjaman; use App\MaxPinjaman;
use Illuminate\Http\Request; use Illuminate\Http\Request;
use Illuminate\Support\Facades\Log;
class MaxPinjamanController extends Controller class MaxPinjamanController extends Controller
{ {
public function getAllMaxPinjaman(){ public function getAllMaxPinjaman(Request $request)
$pinjaman = MaxPinjaman::on('mysql7')->get(); {
if (config('parameter.max_mutuemas')) {
$data = MaxMutuEmas::on('mysql7')->select('karat', 'teller', 'pc', 'operasi')->get();
$calculateMargin = $this->calculateMaxPinjamanMutu($data, $request->mutu,$request->total_nilai_marhun);
$pinjaman = [
[
"user_type" => "teller",
"max" => $calculateMargin['teller'],
"teller_pinjaman" => $calculateMargin['teller_pinjaman']
],
[
"user_type" => "khazanah",
"max" => $calculateMargin['pc'],
"pc_pinjaman" => $calculateMargin['pc_pinjaman']
],
[
"user_type" => "operasi",
"max" => $calculateMargin['operasi'],
"operasi_pinjaman" => $calculateMargin['operasi_pinjaman']
]
];
} else {
$pinjaman = MaxPinjaman::on('mysql7')->get();
}
return response()->json($pinjaman); return response()->json($pinjaman);
} }
public function calculateMaxPinjamanMutu($data, $mutu,$totalMarhun)
{
$totalMaxMarhunPC = 0;
$totalMaxMarhunTeller = 0;
$totalMaxMarhunOperasi = 0;
if($mutu == null || $totalMarhun == 0){
return [
"pc" => 0,
"pc_pinjaman" => 0,
"teller" => 0,
"teller_pinjaman" => 0,
"operasi" => 0,
"operasi_pinjaman" => 0
];
}
$mutuKarat = array_map(function($item) {
return $item[0];
}, $mutu);
$mutuNilai = array_map(function($item) {
return $item[1];
}, $mutu);
foreach($mutuKarat as $index => $karat){
$margin = $data->where('karat', $karat)->first();
if($margin){
$nilai = $mutuNilai[$index];
$totalMaxMarhunPC += round(($margin->pc/100) * $nilai, 2);
$totalMaxMarhunTeller += round(($margin->teller/100) * $nilai, 2);
$totalMaxMarhunOperasi += round(($margin->operasi/100) * $nilai, 2);
}
}
$totalMaxPC = $totalMarhun > 0 ? ($totalMaxMarhunPC / $totalMarhun) * 100 : 0;
$totalMaxTeller = $totalMarhun > 0 ? ($totalMaxMarhunTeller / $totalMarhun) * 100 : 0;
$totalMaxOperasi = $totalMarhun > 0 ? ($totalMaxMarhunOperasi / $totalMarhun) * 100 : 0;
return [
"pc" => round($totalMaxPC,2),
"pc_pinjaman" => round(($totalMaxPC / 100) * $totalMarhun, 2),
"teller" => round($totalMaxTeller,2),
"teller_pinjaman" => round(($totalMaxTeller / 100) * $totalMarhun, 2),
"operasi" => round($totalMaxOperasi,2),
"operasi_pinjaman" => round(($totalMaxOperasi / 100) * $totalMarhun, 2)
];
}
public function getAllMaxMutuEmas(Request $request)
{
$maxmutuemas = MaxMutuEmas::on('mysql7')->get();
return response()->json($maxmutuemas);
}
public function getSpecificMaxMutuEmas(Request $request)
{
$karat = $request->karat;
$nilaimarhun = $request->nilaimarhun;
$nilaimarhun = preg_replace('/[^0-9.]/', '', $nilaimarhun); // Remove non-numeric characters except decimal point
$nilaimarhun = is_numeric($nilaimarhun) ? (float)$nilaimarhun : 0;
$maxmutuemas = MaxMutuEmas::on('mysql7')->where('karat', $karat)->first();
if($maxmutuemas && $nilaimarhun > 0){
$maxmutuemas->maxteller = round(($maxmutuemas->teller/100) * $nilaimarhun, 2);
$maxmutuemas->maxpc = round(($maxmutuemas->pc/100) * $nilaimarhun, 2);
$maxmutuemas->maxoperasi = round(($maxmutuemas->operasi/100) * $nilaimarhun, 2);
} else if($maxmutuemas) {
$maxmutuemas->maxteller = 0;
$maxmutuemas->maxpc = 0;
$maxmutuemas->maxoperasi = 0;
}
return response()->json($maxmutuemas);
}
public function updateMaxMutuEmas(Request $request)
{
// Validate the request manually for Lumen
$validator = \Illuminate\Support\Facades\Validator::make($request->all(), [
'recno' => 'required|integer',
'karat' => 'required|string|max:10',
'keterangan' => 'required|string|max:255',
'teller' => 'required|numeric|min:0|max:100',
'pc' => 'required|numeric|min:0|max:100',
'operasi' => 'required|numeric|min:0|max:100',
'username' => 'required|string|max:255'
], [
'recno.required' => 'Nombor rekod diperlukan.',
'recno.integer' => 'Nombor rekod mesti berupa nombor.',
'karat.required' => 'Karat diperlukan.',
'karat.string' => 'Karat mesti berupa teks.',
'karat.max' => 'Karat tidak boleh lebih dari 10 aksara.',
'keterangan.required' => 'Keterangan diperlukan.',
'keterangan.string' => 'Keterangan mesti berupa teks.',
'keterangan.max' => 'Keterangan tidak boleh lebih dari 255 aksara.',
'teller.required' => 'Peratus teller diperlukan.',
'teller.numeric' => 'Peratus teller mesti berupa nombor.',
'teller.min' => 'Peratus teller mestilah sekurang-kurangnya 0.',
'teller.max' => 'Peratus teller tidak boleh melebihi 100.',
'pc.required' => 'Peratus PC diperlukan.',
'pc.numeric' => 'Peratus PC mesti berupa nombor.',
'pc.min' => 'Peratus PC mestilah sekurang-kurangnya 0.',
'pc.max' => 'Peratus PC tidak boleh melebihi 100.',
'operasi.required' => 'Peratus operasi diperlukan.',
'operasi.numeric' => 'Peratus operasi mesti berupa nombor.',
'operasi.min' => 'Peratus operasi mestilah sekurang-kurangnya 0.',
'operasi.max' => 'Peratus operasi tidak boleh melebihi 100.',
]);
if ($validator->fails()) {
return response()->json([
'status' => 'error',
'message' => 'Pengesahan gagal',
'errors' => $validator->errors()
], 422);
}
$recno = $request->recno;
$karat = $request->karat;
$keterangan = $request->keterangan;
$teller = $request->teller;
$pc = $request->pc;
$operasi = $request->operasi;
$username = $request->username;
$current = \Carbon\Carbon::now();
$maxmutuemas = MaxMutuEmas::on('mysql7')->where('recno', $recno)->first();
if ($maxmutuemas) {
$oldmax = $maxmutuemas->toJson();
$maxmutuemas->karat = $karat;
$maxmutuemas->keterangan = $keterangan;
$maxmutuemas->teller = $teller;
$maxmutuemas->pc = $pc;
$maxmutuemas->operasi = $operasi;
$maxmutuemas->tarikhupdate = \Carbon\Carbon::now();
$maxmutuemas->save();
Audit::create([
'users' => $username,
'actions' => 'Penukaran Mutu Margin',
'norujukan' => '-',
'new_data' => $maxmutuemas->toJson(),
'old_data' => $oldmax,
'kodcaw' => 'OPERASI',
'created_at' => $current,
'updated_at' => $current,
]);
return response()->json([
'status' => 'success',
'message' => 'Max Mutu Emas updated successfully',
'data' => $maxmutuemas
]);
} else {
return response()->json([
'status' => 'error',
'message' => 'Record not found'
], 404);
}
}
} }
@@ -0,0 +1,160 @@
<?php
namespace App\Http\Controllers;
use App\Services\PembiayaanOnline\ModalOnlineService;
use Illuminate\Http\Request;
class ModalOnlineController extends Controller
{
protected $service;
public function __construct(ModalOnlineService $service = null)
{
$this->service = $service ?: new ModalOnlineService();
}
protected function respond(array $result)
{
return response()->json($result['payload'], $result['status']);
}
/**
* GET /api/modal-online/{kodcaw}
* Read-only: does not create today's row.
*/
public function get($kodcaw)
{
return $this->respond($this->service->get($kodcaw));
}
/**
* @deprecated Alias of get() — no longer auto-creates RM100k.
*/
public function getOrCreate($kodcaw)
{
return $this->get($kodcaw);
}
/**
* POST /api/modal-online/{kodcaw}/reserve
*/
public function reserve($kodcaw, Request $request)
{
return $this->respond($this->service->reserve($kodcaw, $request->input('amaun', 0)));
}
/**
* GET /api/initiate/modal-online?zone=all|{zone}
*/
public function initiate(Request $request)
{
return $this->respond($this->service->initiate($request->input('zone', 'all')));
}
/**
* POST /api/modal-online/{kodcaw}/topup/request
* PC mohon had (hari pertama) atau tambah modal. Body: amaun, dimohon_oleh, nota?
*/
public function requestTopUp($kodcaw, Request $request)
{
return $this->respond($this->service->requestTopUp(
$kodcaw,
$request->input('amaun', 0),
$request->input('dimohon_oleh', ''),
$request->input('nota')
));
}
/**
* GET /api/modal-online/{kodcaw}/topup/requests?status=&tarikh=
*/
public function listTopUpByCawangan($kodcaw, Request $request)
{
return $this->respond($this->service->listTopUpRequests(
$kodcaw,
$request->input('status'),
$request->input('tarikh')
));
}
/**
* GET /api/modal-online/operasi/topup/requests?status=PENDING&tarikh=
*/
public function listTopUpOperasi(Request $request)
{
$status = $request->input('status', 'PENDING');
if ($status === 'all' || $status === '') {
$status = null;
}
return $this->respond($this->service->listTopUpRequests(
null,
$status,
$request->input('tarikh')
));
}
/**
* POST /api/modal-online/operasi/topup/{id}/approve
* Body: diluluskan_oleh, nota?, amaun? (optional override)
*/
public function approveTopUp($id, Request $request)
{
return $this->respond($this->service->approveTopUp(
$id,
$request->input('diluluskan_oleh', ''),
$request->input('nota'),
null,
$request->input('amaun')
));
}
/**
* POST /api/modal-online/operasi/topup/{id}/reject
* Body: diluluskan_oleh, nota?
*/
public function rejectTopUp($id, Request $request)
{
return $this->respond($this->service->rejectTopUp(
$id,
$request->input('diluluskan_oleh', ''),
$request->input('nota')
));
}
/**
* POST /api/modal-online/{kodcaw}/close
* Body: ditutup_oleh
*/
public function close($kodcaw, Request $request)
{
return $this->respond($this->service->close(
$kodcaw,
$request->input('ditutup_oleh', '')
));
}
/**
* GET /api/modal-online/operasi/eod?zone=all&tarikh=
*/
public function listToday(Request $request)
{
return $this->respond($this->service->listToday(
$request->input('zone', 'all'),
$request->input('tarikh')
));
}
/**
* POST /api/modal-online/operasi/eod/close-all
* Body: ditutup_oleh, zone?
*/
public function closeAll(Request $request)
{
return $this->respond($this->service->closeAll(
$request->input('ditutup_oleh', ''),
$request->input('zone', 'all')
));
}
}
+198
View File
@@ -0,0 +1,198 @@
<?php
namespace App\Http\Controllers;
use App\Cawangan;
use App\Palsu;
use App\Pampasan;
use App\Panjar;
use App\Tebus;
use Illuminate\Http\Request;
use Carbon\Carbon;
use Illuminate\Log\Logger;
use Illuminate\Support\Facades\Log;
class PampasanController extends Controller
{
public function terimaPampasan(Request $request)
{
$validated = $this->validate($request, [
'norujukan' => 'required|string',
'kodcaw' => 'required|string',
'jumlah_pampasan' => 'required|numeric',
'denominasi' => 'required|array',
'teller' => 'required|string',
]);
try {
$cawangan = $this->getCawangan($request->kodcaw);
if (!$cawangan) {
return $this->errorResponse('Cawangan tidak dijumpai untuk kodcaw: ' . $request->kodcaw, 404);
}
$pampasan = Pampasan::on($cawangan['mysql'])
->where('norujukan', $validated['norujukan'])
->first();
$pampasan->update([
'jumlah_pampasan' => $validated['jumlah_pampasan'],
'denominasi' => isset($validated['denominasi']) ? json_encode($validated['denominasi']) : null,
'teller' => $validated['teller'],
]);
return $this->successResponse('Pampasan berjaya dibayar.', $pampasan, 201);
} catch (\Exception $e) {
return $this->errorResponse('Database error: ' . $e->getMessage(), 500);
}
}
public function updateStatusPampasan(Request $request)
{
$norujukan = $request->norujukan;
$cawangan = $this->getCawangan($request->kodcaw);
if (!$cawangan) {
return $this->errorResponse('Cawangan tidak dijumpai untuk kodcaw: ' . $request->kodcaw, 404);
}
$tebus = Tebus::on($cawangan['mysql'])->where('norujukan', $norujukan)->first();
$pampasan = Pampasan::on($cawangan['mysql'])->where("norujukan", $norujukan)->first();
$pampasan->status = 1;
$pampasan->save();
// Update corresponding palsu table record status to 1
Palsu::on($cawangan['mysql'])
->where('norujukan', $norujukan)
->update(['status' => 1]);
return $this->successResponse('Status Pampasan berjaya dituntut.', $pampasan, 201);
}
public function getPampasan(Request $request)
{
$cawangan_connection = Cawangan::where('kodcaw', $request->kodcaw)->first()->mysql;
$pampasan = Pampasan::on($cawangan_connection)
->when($request->filled('norujukan'), function ($query) use ($request) {
return $query->where('norujukan', $request->norujukan);
})
->get();
return $this->successResponse('Senarai pampasan', $pampasan, 201);
}
public function updateAgreementPrintedAt(Request $request)
{
$validated = $this->validate($request, [
'norujukan' => 'required|string',
'kodcaw' => 'required|string',
]);
try {
$cawangan = $this->getCawangan($validated['kodcaw']);
if (!$cawangan) {
return $this->errorResponse('Cawangan tidak dijumpai untuk kodcaw: ' . $validated['kodcaw'], 404);
}
$pampasan = Pampasan::on($cawangan['mysql'])->where('norujukan', $validated['norujukan'])->first();
if (!$pampasan) {
return $this->errorResponse('Pampasan tidak dijumpai untuk norujukan: ' . $validated['norujukan'], 404);
}
$pampasan->agreement_printed_at = Carbon::now();
$pampasan->save();
return $this->successResponse('Agreement printed timestamp berjaya dikemaskini.', $pampasan, 200);
} catch (\Exception $e) {
return $this->errorResponse('Database error: ' . $e->getMessage(), 500);
}
}
public function initiatePampasan(Request $request)
{
$validated = $this->validate($request, [
'norujukan' => 'required|string',
'kodcaw' => 'required|string',
'teller' => 'required|string',
'baucerno' => 'required|string',
]);
try {
$cawangan = $this->getCawangan($validated['kodcaw']);
if (!$cawangan) {
return $this->errorResponse('Cawangan tidak dijumpai untuk kodcaw: ' . $validated['kodcaw'], 404);
}
// Find the palsu record
$palsu = Palsu::on($cawangan['mysql'])->where('norujukan', $validated['norujukan'])->first();
if (!$palsu) {
return $this->errorResponse('Barang kes tidak dijumpai untuk norujukan: ' . $validated['norujukan'], 404);
}
// Check if pampasan already exists for this norujukan
$existingPampasan = Pampasan::on($cawangan['mysql'])->where('norujukan', $validated['norujukan'])->first();
if ($existingPampasan) {
// If pampasan exists, just update the agreement_printed_at
$existingPampasan->agreement_printed_at = Carbon::now();
$existingPampasan->save();
return $this->successResponse('Agreement printed timestamp berjaya dikemaskini untuk pampasan sedia ada.', $existingPampasan, 200);
}
// Create new pampasan record based on palsu data
$pampasan = Pampasan::on($cawangan['mysql'])->create([
'norujukan' => $palsu->norujukan,
'baucerno' => $validated['baucerno'],
'kodcaw' => $palsu->kodcaw,
'jumlah_pampasan' => $palsu->nilaimarhun,
'teller' => $validated['teller'],
'status' => 0,
'agreement_printed_at' => Carbon::now(),
]);
return $this->successResponse('Pampasan berjaya daftar dari rekod barang kes.', $pampasan, 201);
} catch (\Exception $e) {
return $this->errorResponse('Database error: ' . $e->getMessage(), 500);
}
}
private function getCawangan($kodcaw)
{
$cawangan = Cawangan::on('mysql7')->where('kodcaw', $kodcaw)->first();
if (!$cawangan) {
return null;
}
return $cawangan;
}
private function errorResponse($message, $statusCode = 404)
{
return response()->json([
'success' => false,
'message' => $message,
], $statusCode);
}
private function successResponse($message, $data = null, $statusCode = 200)
{
return response()->json([
'success' => true,
'message' => $message,
'data' => $data,
], $statusCode);
}
}
@@ -0,0 +1,241 @@
<?php
namespace App\Http\Controllers;
use App\Services\PembiayaanOnline\PembiayaanOnlineService;
use Illuminate\Http\Request;
class PembiayaanOnlineController extends Controller
{
protected $service;
public function __construct(PembiayaanOnlineService $service = null)
{
$this->service = $service ?: new PembiayaanOnlineService();
}
protected function respond(array $result)
{
return response()->json($result['payload'], $result['status']);
}
/**
* POST /api/pembiayaan-online/{kodcaw}
*/
public function store($kodcaw, Request $request)
{
return $this->respond($this->service->store($kodcaw, $request->all()));
}
/**
* GET /api/pembiayaan-online/{kodcaw}/by-norujukan/{norujukan}
*/
public function show($kodcaw, $norujukan)
{
return $this->respond($this->service->show($kodcaw, $norujukan));
}
/**
* GET /api/pembiayaan-online/{kodcaw}/lines/{id}
*/
public function showLine($kodcaw, $id)
{
return $this->respond($this->service->showLine($kodcaw, $id));
}
/**
* GET /api/pembiayaan-online/{kodcaw}/queue
*/
public function queue($kodcaw, Request $request)
{
return $this->respond($this->service->queue($kodcaw, $request->input('status')));
}
/**
* PUT /api/pembiayaan-online/{kodcaw}/lines/{id}
*/
public function updateLine($kodcaw, $id, Request $request)
{
// Prefer only present keys so "has" semantics match previous controller.
$input = [];
foreach ([
'kodbank', 'noakaun', 'nama_bank', 'nama_akaun', 'nota',
'bukti_akaun_file_id', 'borang_file_id', 'update_customer_bank',
'bukti_akaun_data', 'bukti_akaun_filename', 'bukti_akaun_type',
] as $key) {
if ($request->has($key)) {
$input[$key] = $request->input($key);
}
}
return $this->respond($this->service->updateLine($kodcaw, $id, $input));
}
/**
* POST /api/pembiayaan-online/{kodcaw}/lines/{id}/verify
*/
public function verifyLine($kodcaw, $id, Request $request)
{
return $this->respond($this->service->verifyLine(
$kodcaw,
$id,
$request->input('pc_verified_by', '')
));
}
/**
* POST /api/pembiayaan-online/{kodcaw}/lines/{id}/unverify
*/
public function unverifyLine($kodcaw, $id)
{
return $this->respond($this->service->unverifyLine($kodcaw, $id));
}
/**
* GET /api/pembiayaan-online/{kodcaw}/batches
*/
public function listBatches($kodcaw, Request $request)
{
return $this->respond($this->service->listBatches(
$kodcaw,
$request->input('tarikh'),
$request->input('status')
));
}
/**
* GET /api/pembiayaan-online/{kodcaw}/batches/{batchId}
*/
public function showBatch($kodcaw, $batchId)
{
return $this->respond($this->service->showBatch($kodcaw, $batchId));
}
/**
* POST /api/pembiayaan-online/{kodcaw}/batches/submit
*/
public function submitBatch($kodcaw, Request $request)
{
return $this->respond($this->service->submitBatch(
$kodcaw,
$request->input('ids', []),
$request->input('pc_submitted_by', ''),
$request->input('slot')
));
}
/**
* GET /api/pembiayaan-online/operasi/batches
*/
public function operasiListBatches(Request $request)
{
return $this->respond($this->service->operasiListBatches(
$request->input('status', 'SUBMITTED'),
$request->input('tarikh')
));
}
/**
* GET /api/pembiayaan-online/operasi/{kodcaw}/batches/{batchId}
*/
public function operasiShowBatch($kodcaw, $batchId)
{
return $this->showBatch($kodcaw, $batchId);
}
/**
* POST /api/pembiayaan-online/operasi/{kodcaw}/lines/{id}/approve
*/
public function operasiApproveLine($kodcaw, $id, Request $request)
{
return $this->respond($this->service->operasiApproveLine(
$kodcaw,
$id,
$request->input('ops_by', '')
));
}
/**
* POST /api/pembiayaan-online/operasi/{kodcaw}/lines/{id}/reject
*/
public function operasiRejectLine($kodcaw, $id, Request $request)
{
return $this->respond($this->service->operasiRejectLine(
$kodcaw,
$id,
$request->input('ops_by', ''),
$request->input('reject_reason', '')
));
}
/**
* POST /api/pembiayaan-online/operasi/{kodcaw}/batches/{batchId}/approve
*/
public function operasiApproveBatch($kodcaw, $batchId, Request $request)
{
return $this->respond($this->service->operasiApproveBatch(
$kodcaw,
$batchId,
$request->input('ops_by', '')
));
}
/**
* POST /api/pembiayaan-online/operasi/{kodcaw}/lines/{id}/paid
* Body: ops_by, no_rujukan_bayaran, tarikh_bayaran?,
* bukti_data + bukti_filename + bukti_type OR bukti_file_id
*/
public function operasiMarkPaid($kodcaw, $id, Request $request)
{
return $this->respond($this->service->operasiMarkPaid($kodcaw, $id, $request->all()));
}
/**
* POST /api/pembiayaan-online/operasi/{kodcaw}/batches/{batchId}/paid
*/
public function operasiMarkPaidBatch($kodcaw, $batchId, Request $request)
{
return $this->respond($this->service->operasiMarkPaidBatch($kodcaw, $batchId, $request->all()));
}
/**
* GET /api/pembiayaan-online/{kodcaw}/lines/{id}/bukti
*/
public function getBukti($kodcaw, $id)
{
return $this->respond($this->service->getBukti($kodcaw, $id));
}
/**
* GET /api/pembiayaan-online/{kodcaw}/lines/{id}/bukti-akaun
*/
public function getBuktiAkaun($kodcaw, $id)
{
return $this->respond($this->service->getBuktiAkaun($kodcaw, $id));
}
/**
* GET /api/pembiayaan-online/{kodcaw}/paid?blast_sent=0
*/
public function paidQueue($kodcaw, Request $request)
{
return $this->respond($this->service->paidQueue(
$kodcaw,
$request->input('blast_sent')
));
}
/**
* POST /api/pembiayaan-online/{kodcaw}/paid/blast
* Body: ids[] (or ids), blast_by?
*/
public function markBlastSent($kodcaw, Request $request)
{
$ids = $request->input('ids', $request->input('id'));
return $this->respond($this->service->markBlastSent(
$kodcaw,
$ids,
$request->input('blast_by')
));
}
}
@@ -11,6 +11,11 @@ use Illuminate\Http\Request;
use Illuminate\Support\Facades\DB; use Illuminate\Support\Facades\DB;
use App\Services\Reports\GadaianService as ReportGadaianService; use App\Services\Reports\GadaianService as ReportGadaianService;
use App\Helper; use App\Helper;
use Carbon\Carbon;
use App\Pekerjaan;
use App\Poskod;
use App\TransactionOnline;
use Log;
use App\Services\Reports\RingkasanHarianService as ReportRingkasanHarianService; use App\Services\Reports\RingkasanHarianService as ReportRingkasanHarianService;
@@ -162,11 +167,484 @@ public function getSummaryLaporanPelangganAktif(Request $request)
return response()->json($response); return response()->json($response);
} }
public function getActiveCawanganConnections()
{
$cawangan_details = Cawangan::select(['details_caw', 'mysql'])->get();
$cawangan_details = $cawangan_details->filter(fn($x) => !in_array(strtolower($x->details_caw), config('report.excluded_cawangan')));
$connection_active_cawangan = Helper::getActiveCawanganDbConnection();
return collect($cawangan_details->filter(fn($x) => in_array($x->mysql, $connection_active_cawangan)));
}
public function getSummaryLaporanDataPelanggan(Request $request)
{
$year = $request->year;
if (!$year) {
return response()->json(['error' => 'Sila pilih tahun'], 400);
}
$startOfYear = Carbon::create($year, 1, 1)->startOfDay();
$endOfYear = Carbon::create($year, 12, 31)->endOfDay();
Carbon::setLocale('ms');
// 1️⃣ Ambil semua pelanggan tahun ini
$pelanggan = Customer::whereYear('tarikhdaftar', $year)
->select('id','nama','kpbaru','kplama','t_lahir','jantina',
'kodkerja','poskod','kodcaw','tarikhdaftar','tujuangadai','nopelanggan')
->get();
$connections = $this->getActiveCawanganConnections();
// Ambil semua pekerjaan & poskod sekali untuk map cepat
$pekerjaanAll = Pekerjaan::pluck('keterangan','kodkerja');
$poskodAll = Poskod::with('daerah')->get()->keyBy('poskod');
// 2️⃣ Ambil semua nokp pelanggan
$nokps = $pelanggan->map(fn($p) => $p->kpbaru ?? $p->kplama)->filter()->values();
// 3️⃣ Ambil semua transaksi gadai + tebus untuk nokp tu dari semua cawangan
$allTransaksi = collect();
foreach ($connections as $conn) {
$data = DB::connection($conn->mysql)
->table('gadai as g')
->leftJoin('tebus as t', 'g.norujukan', '=', 't.norujukan')
->leftJoin('lelong as l', 'g.norujukan', '=', 'l.norujukan')
->whereIn('g.nokp', $nokps)
->whereBetween('g.t_gadai', [$startOfYear, $endOfYear]) // ⬅️ dalam tahun sahaja
->select(
'g.nokp',
'g.norujukan',
'g.t_gadai',
't.t_tebus',
'g.pinjaman',
'g.upah12',
'g.tempoh',
'l.t_lelong',
'g.sttebus',
)
->get();
$allTransaksi = $allTransaksi->concat($data);
}
// 4️⃣ Group by nokp
$transGrouped = $allTransaksi->groupBy('nokp');
// 5️⃣ Ambil semua norujukan transaksi online
$onlineNorujukan = TransactionOnline::pluck('norujukan')->unique()->values();
// 6️⃣ Map pelanggan
$result = $pelanggan->map(function($row) use ($transGrouped, $onlineNorujukan, $pekerjaanAll, $poskodAll, $year) {
$nokp = $row->kpbaru ?? $row->kplama ?? null;
$tempohData = $transGrouped->get($nokp, collect());
// Norujukan pelanggan spesifik
$norujukanPelanggan = $tempohData->pluck('norujukan')->unique()->values();
// Cara Bayaran
// $caraBayaran = $norujukanPelanggan->intersect($onlineNorujukan)->isNotEmpty() ? 'Online' : 'Kaunter';
$adaOnline = $norujukanPelanggan->contains(fn($nr) => isset($onlineNorujukan[$nr]));
$caraBayaran = $adaOnline ? 'Online' : 'Kaunter';
if ($adaOnline) {
\Log::info("Pelanggan {$row->nama} ({$nokp}): Bayaran Online - YA");
}
// Bilangan transaksi
$bilTransaksi = $tempohData->count();
// Bilangan Belum tebus
$endOfYear = Carbon::create($year, 12, 31)->endOfDay();
$bilOutstanding = $tempohData
->filter(function ($row) use ($endOfYear) {
// masih belum tebus langsung
if (empty($row->sttebus)) {
return true;
}
// dah tebus, tapi tebus selepas hujung tahun
return Carbon::parse($row->t_tebus)->gt($endOfYear);
})
->count();
// Bilangan tebus
$bilTebus = $tempohData->whereNotNull('t_tebus')->count();
// Jumlah pinjaman
$jumlahPinjaman = $tempohData->sum('pinjaman');
// Jumlah ujrah ikut tempoh surat
$jumlahUjrah = $tempohData->reduce(function ($carry, $trx) {
if (!$trx->upah12 || !$trx->tempoh) return $carry;
return $carry + ($trx->upah12 / 12 * $trx->tempoh);
}, 0);
// Tarikh mula & tamat
$tarikhMula = $tempohData->min('t_gadai');
$tarikhTamat = $tempohData->max('t_tebus');
$tarikhLelong = $tempohData->max('t_lelong');
// Tempoh Pajakan
if (!$tarikhMula) {
$tempohPajakan = '-';
} elseif (!$tarikhTamat || $tarikhMula == $tarikhTamat) {
$tempohPajakan = Carbon::parse($tarikhMula)->translatedFormat('M Y');
} else {
$tempohPajakan = Carbon::parse($tarikhMula)->translatedFormat('M Y') .
' - ' .
Carbon::parse($tarikhTamat)->translatedFormat('M Y');
}
// Hari sejak transaksi terakhir
$hariTempohPajakan = $tarikhMula
? Carbon::parse($tarikhMula)->diffInDays($tarikhTamat ? Carbon::parse($tarikhTamat) : Carbon::now())
: null;
// Tujuan gadai
$tujuangadai = $row->tujuangadai ?: '-';
// Status aktif: ada transaksi dalam tahun tu
$now = Carbon::now();
$endOfYear = Carbon::create($year, 12, 31)->endOfDay();
$startOfYear = Carbon::create($year, 1, 1)->startOfDay();
$statusAktif = $tempohData->contains(function ($trx) use ($startOfYear, $endOfYear) {
if (!$trx->t_gadai) return false;
$tGadai = Carbon::parse($trx->t_gadai);
$tTebus = $trx->t_tebus ? Carbon::parse($trx->t_tebus) : null;
// SAG wujud dalam tahun laporan
return
$tGadai->lte($endOfYear) &&
(
is_null($tTebus) || // belum ditebus
$tTebus->gte($startOfYear) // ditebus dalam / selepas tahun
);
});
// Umur
$umur = $row->t_lahir ? Carbon::parse($row->t_lahir)->age : null;
// Pekerjaan
$pekerjaan = $row->kodkerja
? ($pekerjaanAll[ltrim($row->kodkerja,'0')] ?? 'Lain-lain')
: '-';
// Daerah / lokasi
$lokasi = $row->poskod && isset($poskodAll[$row->poskod])
? $poskodAll[$row->poskod]->daerah->namadaerah ?? 'Lain-lain'
: 'Lain-lain';
return [
'cawangan' => $row->kodcaw ?? '-',
'nama' => $row->nama,
'nopelanggan' => $row->nopelanggan,
'nokp' => $nokp ?? '-',
'tarikhdaftar' => Carbon::parse($row->tarikhdaftar)->format('d-m-Y'),
'umur' => $umur,
'jantina' => $row->jantina ?? '-',
'pekerjaan' => $pekerjaan,
'daerah' => $lokasi,
'tempoh_pajakan' => $tempohPajakan,
'tarikh_mula' => $tarikhMula ? Carbon::parse($tarikhMula)->format('d-m-Y') : null,
'tarikh_tamat' => $tarikhTamat ? Carbon::parse($tarikhTamat)->format('d-m-Y') : null,
'hari_sejak_transaksi' => $hariTempohPajakan,
'bil_transaksi' => $bilTransaksi,
'bil_outstanding' => $bilOutstanding,
'bil_tebus' => $bilTebus,
'jumlah_pinjaman' => $jumlahPinjaman,
'norujukan' => $norujukanPelanggan,
'jumlah_ujrah' => $jumlahUjrah,
'tujuan_gadai' => $tujuangadai,
'status_aktif' => $statusAktif ? 'AKTIF' : 'TIDAK AKTIF',
'cara_bayaran' => $caraBayaran,
'tarikh_lelong' => $tarikhLelong ? Carbon::parse($tarikhLelong)->format('d-m-Y') : null,
];
});
return response()->json([
'year' => $year,
'summary' => [
'total_pelanggan' => $result->count(),
'jumlah_cawangan' => $result->pluck('cawangan')->unique()->count(),
],
'pelanggan' => $result->values(),
], 200);
}
private function formatTempohPajakan($start, $end)
{
if (!$start || !$end) {
return '-';
}
$mula = Carbon::parse($start);
$tamat = Carbon::parse($end);
if ($mula->year === $tamat->year) {
return $mula->translatedFormat('M') . ' – ' .
$tamat->translatedFormat('M Y');
}
return $mula->translatedFormat('M Y') . ' – ' .
$tamat->translatedFormat('M Y');
}
public function getSummaryLaporanDataPelangganBycaw(Request $request)
{
$year = $request->year;
if (!$year) {
return response()->json(['error' => 'Sila pilih tahun'], 400);
}
// ===============================
// INPUT CAWANGAN (MULTIPLE)
// ===============================
$cawangan = $request->input('cawangan', []);
if (!is_array($cawangan)) {
$cawangan = [$cawangan];
}
$startOfYear = Carbon::create($year, 1, 1)->startOfDay();
$endOfYear = Carbon::create($year, 12, 31)->endOfDay();
Carbon::setLocale('ms');
// ===============================
// 1️⃣ AMBIL PELANGGAN (FILTER CAWANGAN)
// ===============================
$pelangganQuery = Customer::whereYear('tarikhdaftar', $year);
if (!empty($cawangan)) {
$pelangganQuery->whereIn('kodcaw', $cawangan);
}
$pelanggan = $pelangganQuery
->select(
'id','nama','kpbaru','kplama','t_lahir','jantina',
'kodkerja','poskod','kodcaw','tarikhdaftar',
'tujuangadai','nopelanggan'
)
->get();
if ($pelanggan->isEmpty()) {
return response()->json([
'year' => $year,
'summary' => [
'total_pelanggan' => 0,
'jumlah_cawangan' => 0,
],
'pelanggan' => []
], 200);
}
// ===============================
// 2️⃣ CONNECTION CAWANGAN
// ===============================
$connections = $this->getActiveCawanganConnections();
// ===============================
// 3️⃣ MASTER DATA
// ===============================
$pekerjaanAll = Pekerjaan::pluck('keterangan', 'kodkerja');
$poskodAll = Poskod::with('daerah')->get()->keyBy('poskod');
// ===============================
// 4️⃣ NOKP PELANGGAN
// ===============================
$nokps = $pelanggan
->map(fn($p) => $p->kpbaru ?? $p->kplama)
->filter()
->values();
// ===============================
// 5️⃣ TRANSAKSI GADAI / TEBUS
// ===============================
$allTransaksi = collect();
foreach ($connections as $conn) {
$data = DB::connection($conn->mysql)
->table('gadai as g')
->leftJoin('tebus as t', 'g.norujukan', '=', 't.norujukan')
->leftJoin('lelong as l', 'g.norujukan', '=', 'l.norujukan')
->whereIn('g.nokp', $nokps)
->whereBetween('g.t_gadai', [$startOfYear, $endOfYear])
->select(
'g.nokp',
'g.norujukan',
'g.t_gadai',
't.t_tebus',
'g.pinjaman',
'g.upah12',
'g.tempoh',
'l.t_lelong',
'g.sttebus'
)
->get();
$allTransaksi = $allTransaksi->concat($data);
}
$transGrouped = $allTransaksi->groupBy('nokp');
// ===============================
// 6️⃣ NORUJUKAN BAYARAN ONLINE
// ===============================
$onlineNorujukan = TransactionOnline::pluck('norujukan')->unique();
// ===============================
// 7️⃣ MAP DATA PELANGGAN
// ===============================
$result = $pelanggan->map(function ($row) use (
$transGrouped,
$onlineNorujukan,
$pekerjaanAll,
$poskodAll,
$year
) {
$nokp = $row->kpbaru ?? $row->kplama;
$tempohData = $transGrouped->get($nokp, collect());
$norujukanPelanggan = $tempohData->pluck('norujukan')->unique();
// Cara Bayaran
$adaOnline = $norujukanPelanggan
->intersect($onlineNorujukan)
->isNotEmpty();
$caraBayaran = $adaOnline ? 'Online' : 'Kaunter';
// Bilangan
$bilTransaksi = $tempohData->count();
$bilOutstanding = $tempohData->filter(function ($row) use ($year) {
$endOfYear = Carbon::create($year, 12, 31)->endOfDay();
if (empty($row->sttebus)) return true;
return Carbon::parse($row->t_tebus)->gt($endOfYear);
})->count();
$bilTebus = $tempohData->whereNotNull('t_tebus')->count();
// Jumlah
$jumlahPinjaman = $tempohData->sum('pinjaman');
$jumlahUjrah = $tempohData->reduce(function ($carry, $trx) {
if (!$trx->upah12 || !$trx->tempoh) return $carry;
return $carry + ($trx->upah12 / 12 * $trx->tempoh);
}, 0);
// Tarikh
$tarikhMula = $tempohData->min('t_gadai');
$tarikhTamat = $tempohData->max('t_tebus');
$tarikhLelong = $tempohData->max('t_lelong');
// Tempoh Pajakan
if (!$tarikhMula) {
$tempohPajakan = '-';
} elseif (!$tarikhTamat || $tarikhMula == $tarikhTamat) {
$tempohPajakan = Carbon::parse($tarikhMula)->translatedFormat('M Y');
} else {
$tempohPajakan =
Carbon::parse($tarikhMula)->translatedFormat('M Y') .
' - ' .
Carbon::parse($tarikhTamat)->translatedFormat('M Y');
}
// Hari sejak transaksi terakhir
$hariTempohPajakan = $tarikhMula
? Carbon::parse($tarikhMula)->diffInDays($tarikhTamat ? Carbon::parse($tarikhTamat) : Carbon::now())
: null;
// Tujuan gadai
$tujuangadai = $row->tujuangadai ?: '-';
// Status aktif: ada transaksi dalam tahun tu
$now = Carbon::now();
// Status Aktif
$startOfYear = Carbon::create($year, 1, 1)->startOfDay();
$endOfYear = Carbon::create($year, 12, 31)->endOfDay();
$statusAktif = $tempohData->contains(function ($trx) use ($startOfYear, $endOfYear) {
if (!$trx->t_gadai) return false;
$tGadai = Carbon::parse($trx->t_gadai);
$tTebus = $trx->t_tebus ? Carbon::parse($trx->t_tebus) : null;
return $tGadai->lte($endOfYear) &&
(is_null($tTebus) || $tTebus->gte($startOfYear));
});
// Umur
$umur = $row->t_lahir ? Carbon::parse($row->t_lahir)->age : null;
// Pekerjaan
$pekerjaan = $row->kodkerja
? ($pekerjaanAll[ltrim($row->kodkerja, '0')] ?? 'Lain-lain')
: '-';
// Daerah
$lokasi = $row->poskod && isset($poskodAll[$row->poskod])
? ($poskodAll[$row->poskod]->daerah->namadaerah ?? 'Lain-lain')
: 'Lain-lain';
return [
'cawangan' => $row->kodcaw,
'nama' => $row->nama,
'nopelanggan' => $row->nopelanggan,
'nokp' => $nokp,
'tarikhdaftar' => Carbon::parse($row->tarikhdaftar)->format('d-m-Y'),
'umur' => $umur,
'jantina' => $row->jantina,
'pekerjaan' => $pekerjaan,
'daerah' => $lokasi,
'tempoh_pajakan' => $tempohPajakan,
'tarikh_mula' => $tarikhMula ? Carbon::parse($tarikhMula)->format('d-m-Y') : null,
'tarikh_tamat' => $tarikhTamat ? Carbon::parse($tarikhTamat)->format('d-m-Y') : null,
'hari_sejak_transaksi' => $hariTempohPajakan,
'bil_transaksi' => $bilTransaksi,
'bil_outstanding' => $bilOutstanding,
'bil_tebus' => $bilTebus,
'jumlah_pinjaman' => $jumlahPinjaman,
'jumlah_ujrah' => $jumlahUjrah,
'tujuan_gadai' => $tujuangadai,
'cara_bayaran' => $caraBayaran,
'status_aktif' => $statusAktif ? 'AKTIF' : 'TIDAK AKTIF',
'tarikh_lelong' => $tarikhLelong
? Carbon::parse($tarikhLelong)->format('d-m-Y')
: null,
];
});
$result = $result->sortBy('cawangan')->values();
return response()->json([
'year' => $year,
'cawangan' => $cawangan,
'summary' => [
'total_pelanggan' => $result->count(),
'jumlah_cawangan' => $result->pluck('cawangan')->unique()->count(),
],
'pelanggan' => $result,
], 200);
}
} }
@@ -0,0 +1,78 @@
<?php
namespace App\Http\Controllers\Reports;
use App\Http\Controllers\Controller;
use Illuminate\Http\Request;
use App\Audit;
class AuditTrailController extends Controller
{
public function getAuditTrail(Request $request)
{
$limit = $request->get('limit', 100);
$audit_trails = Audit::query()
->when($request->filled('norujukan'), fn($q) => $q->where('norujukan', $request->norujukan))
->when($request->filled('actions'), fn($q) => $q->where('actions', $request->actions))
->orderBy('created_at', 'desc')
->limit($limit)
->get();
return response()->json($audit_trails);
}
public function AuditTrailOperasi(Request $request)
{
$date_first = $request->get('date', null);
$date_till = $request->get('date_till', null);
$audit_trails = Audit::query()
->where('kodcaw', 'operasi')
->whereDate('created_at', '>=', $date_first)
->whereDate('created_at', '<=', $date_till)
->orderBy('created_at', 'asc')
->get();
$audit_trails->map(function ($audit) {
// Convert from UTC to Malaysia timezone (UTC+8)
$audit->created_at = $audit->created_at->format('Y-m-d H:i:s');
// Get differences between old_data and new_data
$old_data = json_decode($audit->old_data, true) ?? [];
$new_data = json_decode($audit->new_data, true) ?? [];
$differences = [];
// Find changed fields
foreach ($new_data as $key => $new_value) {
if ($key === 'tarikhupdate') continue;
$old_value = $old_data[$key] ?? null;
if ($old_value !== $new_value) {
$differences[$key] = [
'old' => $old_value,
'new' => $new_value
];
}
}
// Check for removed fields
foreach ($old_data as $key => $old_value) {
if ($key === 'tarikhupdate') continue;
if (!array_key_exists($key, $new_data)) {
$differences[$key] = [
'old' => $old_value,
'new' => null
];
}
}
$audit->differences = $differences;
return $audit;
});
return response()->json($audit_trails);
}
}
@@ -48,7 +48,7 @@ class GadaianController extends Controller
$summary_gadaian_data = array_map(function ($db_connection) use ($request) { $summary_gadaian_data = array_map(function ($db_connection) use ($request) {
$query = Gadai::on($db_connection); $query = Gadai::on($db_connection);
$query->select(DB::raw('count(norujukan) as total_gadaian, sum(berat) as sum_berat, sum(nilaimarhun) as sum_nilai_marhun, sum(pinjaman) as sum_pinjaman')); $query->select(DB::raw('count(norujukan) as total_gadaian, sum(berat) as sum_berat, sum(nilaimarhun) as sum_nilai_marhun, sum(pinjaman) as sum_pinjaman, sum(upah12) as sum_upah_12'));
$query->when($request->filled('startDate') and $request->filled('endDate'), function ($q) use ($request) { $query->when($request->filled('startDate') and $request->filled('endDate'), function ($q) use ($request) {
return $q->where('t_gadai', '>=', $request->startDate) return $q->where('t_gadai', '>=', $request->startDate)
@@ -60,6 +60,7 @@ class LelonganController extends Controller
sum(lelong.cajlain) as sum_cajlain, sum(lelong.cajlain) as sum_cajlain,
sum(lelong.cajlelong) as sum_cajlelong, sum(lelong.cajlelong) as sum_cajlelong,
sum(lelong.hargajual) as sum_hargajual, sum(lelong.hargajual) as sum_hargajual,
sum(lelong.hargaasas) as sum_hargaasas,
sum(lelong.baki) as sum_baki')); sum(lelong.baki) as sum_baki'));
@@ -46,10 +46,17 @@ class OutstandingController extends Controller
// Query outstanding summary for each branch // Query outstanding summary for each branch
$summary_Outstanding_data = array_map(function ($db_connection) use ($endDate) { $summary_Outstanding_data = array_map(function ($db_connection) use ($endDate) {
// SAG KES
$queryKes = Gadai::on($db_connection)
->selectRaw('COUNT(norujukan) as total_gadaian_kes, SUM(pinjaman) as sum_pinjaman_kes')
->where('tagbaru', 0)
->where('tagpalsu', 1)
->where('sttebus', '');
// SAG LAMA // SAG LAMA
$queryLama = Gadai::on($db_connection) $queryLama = Gadai::on($db_connection)
->selectRaw('COUNT(norujukan) as total_gadaian, SUM(pinjaman) as sum_pinjaman') ->selectRaw('COUNT(norujukan) as total_gadaian, SUM(pinjaman) as sum_pinjaman')
->where('tagbaru', 0) ->where('tagbaru', 0)
->where('tagpalsu', 0)
->where('sttebus', ''); ->where('sttebus', '');
// SAG BARU // SAG BARU
@@ -64,12 +71,14 @@ class OutstandingController extends Controller
->where('sttebus', ''); ->where('sttebus', '');
if (!empty($endDate)) { if (!empty($endDate)) {
$queryKes->where('t_gadai', '<=', $endDate);
$queryLama->where('t_gadai', '<=', $endDate); $queryLama->where('t_gadai', '<=', $endDate);
$queryBaru->where('t_gadai', '<=', $endDate); $queryBaru->where('t_gadai', '<=', $endDate);
$queryAll->where('t_gadai', '<=', $endDate); $queryAll->where('t_gadai', '<=', $endDate);
} }
return array_merge( return array_merge(
$queryKes->first()->toArray(),
$queryLama->first()->toArray(), $queryLama->first()->toArray(),
$queryBaru->first()->toArray(), $queryBaru->first()->toArray(),
$queryAll->first()->toArray() $queryAll->first()->toArray()
@@ -118,10 +127,12 @@ class OutstandingController extends Controller
if (!empty($endDate)) { if (!empty($endDate)) {
$queryAll->where('tarikh', '=', $endDate); $queryAll->where('tarikh', '=', $endDate);
} }
$record = $queryAll->first();
return array_merge(
$queryAll->first()->toArray() return $record
); ? $record->toArray()
: ['bakieod' => 0];
}, $active_cawangan_db_connection); }, $active_cawangan_db_connection);
// Combine data with branch info // Combine data with branch info
@@ -0,0 +1,129 @@
<?php
namespace App\Http\Controllers\Reports;
use App\Http\Controllers\Controller;
use App\Cawangan;
use App\Gadai;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\DB;
use App\Services\Reports\GadaianService as ReportGadaianService;
use App\Helper;
use App\Tebus;
use Illuminate\Support\Carbon;
class SaringanGadaianController extends Controller
{
public function getLaporanGadai(Request $request)
{
$startDate = $request->startDate ?? now()->startOfMonth()->toDateString();
$endDate = $request->endDate ?? now()->endOfMonth()->toDateString();
$active_dbs = Helper::getActiveCawanganDbConnection();
$cawangan = Cawangan::select('kodcaw', 'details_caw', 'mysql')
->whereIn('mysql', $active_dbs)
->get();
$responses = [];
foreach ($cawangan as $caw) {
$db = $caw->mysql;
$tgb = Tebus::on($db)
->join('gadai as g1', 'tebus.norujukan', '=', 'g1.norujukan')
->join('gadai as g2', function ($join) {
$join->on('g2.nokp', '=', 'g1.nokp')
->on('g2.t_gadai', '=', 'tebus.t_tebus')
->whereRaw('ABS(g2.berat - g1.berat) <= 0.02')
->whereColumn('g2.norujukan', '!=', 'g1.norujukan');
})
->whereBetween('tebus.t_tebus', [$startDate, $endDate])
->groupBy('tebus.norujukan')
->selectRaw("
tebus.norujukan as norujukan_tebus,
MAX(g2.norujukan) as norujukan_gadai_balik,
MAX(g2.nokp) as nokp,
MAX(g2.berat) as berat,
MAX(g2.nilaimarhun) as nilaimarhun,
MAX(g2.pinjaman) as pinjaman,
MAX(g2.t_gadai) as t_gadai,
MAX(g1.taglel) as taglel_lama
")
->get()
->map(function ($row) {
return [
'norujukan_tebus' => $row->norujukan_tebus,
'norujukan_gadai_balik' => $row->norujukan_gadai_balik,
'nokp' => $row->nokp,
'berat' => (float) $row->berat,
'nilaimarhun' => (float) $row->nilaimarhun,
'pinjaman' => (float) $row->pinjaman,
'taglel_lama' => $row->taglel_lama,
't_gadai' => $row->t_gadai,
'jenis' => $row->taglel_lama == 1 ? 'TGB_LELONG' : 'TGB_BIASA',
];
})
->toArray();
$tgb_norujukan = array_column($tgb, 'norujukan_gadai_balik');
$gadai_biasa = DB::connection($db)
->table('gadai')
->whereBetween('t_gadai', [$startDate, $endDate])
->whereNotIn('norujukan', $tgb_norujukan)
->select([
DB::raw('NULL as norujukan_tebus'),
'norujukan as norujukan_gadai_balik',
'nokp',
'berat',
'nilaimarhun',
'pinjaman',
DB::raw('NULL as taglel_lama'),
't_gadai',
])
->get()
->map(function ($row) {
return [
'norujukan_tebus' => null,
'norujukan_gadai_balik' => $row->norujukan_gadai_balik,
'nokp' => $row->nokp,
'berat' => (float) $row->berat,
'nilaimarhun' => (float) $row->nilaimarhun,
'pinjaman' => (float) $row->pinjaman,
'taglel_lama' => null,
't_gadai' => $row->t_gadai,
'jenis' => 'GADAI_BIASA',
];
})
->toArray();
$details = collect($tgb)
->merge($gadai_biasa)
->unique('norujukan_gadai_balik')
->sortBy(['jenis', 't_gadai'])
->values()
->all();
$responses[] = [
'kodcaw' => $caw->kodcaw,
'details_caw' => $caw->details_caw,
'jumlah_surat' => count($details),
'total_tgb_lelong' => collect($details)->where('jenis', 'TGB_LELONG')->count(),
'total_tgb_biasa' => collect($details)->where('jenis', 'TGB_BIASA')->count(),
'total_gadai_biasa' => collect($details)->where('jenis', 'GADAI_BIASA')->count(),
'sum_berat' => collect($details)->sum('berat'),
'sum_nilai_marhun' => collect($details)->sum('nilaimarhun'),
'sum_pinjaman' => collect($details)->sum('pinjaman'),
'details' => $details,
];
}
return response()->json($responses);
}
}
@@ -2,9 +2,11 @@
namespace App\Http\Controllers\Reports; namespace App\Http\Controllers\Reports;
use App\Cawangan; use App\Cawangan;
use App\Gadai;
use App\Helper; use App\Helper;
use App\Http\Controllers\Controller; use App\Http\Controllers\Controller;
use Illuminate\Http\Request; use Illuminate\Http\Request;
use Carbon\Carbon;
class StokAuditController extends Controller class StokAuditController extends Controller
{ {
@@ -38,6 +40,40 @@ class StokAuditController extends Controller
public function getSummaryLaporanStokAudit(Request $request) public function getSummaryLaporanStokAudit(Request $request)
{ {
$connections = $this->getActiveCawanganConnections();
// MODE 1: TARIKH SEMASA
if ($request->dateOption === 'current') {
$today = Carbon::today();
$total_audit = $connections->map(function ($connection) {
$data = Gadai::on($connection->mysql)
->where('tagpalsu', 0)
->where(function($q) {
$q->where('sttebus', '')
->orWhereNull('sttebus');
})
->get();
return [
'cawangan' => $connection->details_caw,
'bilangan_pembiayaan' => $data->count(),
'berat' => $data->sum('berat'),
'nilai_marhun' => $data->sum('nilaimarhun'),
'baki_pembiayaan' => $data->sum('bakipjm'),
'pembiayaan' => $data->sum('pinjaman'),
'upah_belum_bayar' => $data->sum('upahblmbyar'),
'total_utg_onepercent' => 0,
'total_ujrah' => $data->sum('ujrah'),
];
});
}
// MODE 2: BULAN TERTENTU
else {
$month = $request->month; $month = $request->month;
$year = $request->year; $year = $request->year;
@@ -59,34 +95,24 @@ class StokAuditController extends Controller
'total_ujrah' => $data->sum('ujrah'), 'total_ujrah' => $data->sum('ujrah'),
]; ];
}); });
}
$getTotalAcrossCawangan = function($property) use($total_audit) { // TOTAL SEMUA CAWANGAN
$total = array_reduce($total_audit->toArray(), function($carry, $subarray) use($property) { $total_all = [
return $carry + $subarray[$property];
}, 0);
return $total;
};
$total_all_cawangan_audit = [
'cawangan' => 'Total Semua Cawangan', 'cawangan' => 'Total Semua Cawangan',
'bilangan_pembiayaan' => $getTotalAcrossCawangan('bilangan_pembiayaan'), 'bilangan_pembiayaan' => $total_audit->sum('bilangan_pembiayaan'),
'berat' => $getTotalAcrossCawangan('berat'), 'berat' => $total_audit->sum('berat'),
'nilai_marhun' => $getTotalAcrossCawangan('nilai_marhun'), 'nilai_marhun' => $total_audit->sum('nilai_marhun'),
'baki_pembiayaan' => $getTotalAcrossCawangan('baki_pembiayaan'), 'baki_pembiayaan' => $total_audit->sum('baki_pembiayaan'),
'pembiayaan' => $getTotalAcrossCawangan('pembiayaan'), 'pembiayaan' => $total_audit->sum('pembiayaan'),
'upah_belum_bayar' => $getTotalAcrossCawangan('upah_belum_bayar'), 'upah_belum_bayar' => $total_audit->sum('upah_belum_bayar'),
'total_utg_onepercent' => $getTotalAcrossCawangan('total_utg_onepercent'), 'total_utg_onepercent' => $total_audit->sum('total_utg_onepercent'),
'total_ujrah' => $getTotalAcrossCawangan('total_ujrah'), 'total_ujrah' => $total_audit->sum('total_ujrah'),
]; ];
$total_audit->push($total_all_cawangan_audit); $total_audit->push($total_all);
if (sizeof($total_audit) == 0) { return response()->json($total_audit, 200);
return response()->json('failed', 200);
} else {
return response()->json($total_audit, 200);
}
} }
} }
@@ -475,6 +475,9 @@ class StokAuditController extends Controller
// Filter audit // Filter audit
$rekodaudit = $audit->filter(function ($item) use ($tarikhTerkiniT, $tarikhTerkiniA) { $rekodaudit = $audit->filter(function ($item) use ($tarikhTerkiniT, $tarikhTerkiniA) {
if ($item->lelong_tawarruq == 0) {
return true;
}
$norujukan = $item->norujukan; $norujukan = $item->norujukan;
$adaTebusTerkini = isset($tarikhTerkiniT[$norujukan]) && $adaTebusTerkini = isset($tarikhTerkiniT[$norujukan]) &&
+75 -4
View File
@@ -20,6 +20,7 @@ use App\Panjar;
use App\HargaEmas; use App\HargaEmas;
use App\Moratorium; use App\Moratorium;
use App\Audit; use App\Audit;
use App\Feature;
use App\LookupWakil; use App\LookupWakil;
use App\StokAudit1; use App\StokAudit1;
@@ -193,7 +194,7 @@ class TebusController extends Controller
$cawangan = Cawangan::on('mysql7')->where('kodcaw','=',$kodcaw)->first(); $cawangan = Cawangan::on('mysql7')->where('kodcaw','=',$kodcaw)->first();
$tebus_data = Tebus::on($cawangan['mysql']) $tebus_data = Tebus::on($cawangan['mysql'])
->select('tebus.t_tebus', 'gad.t_gadai','gad.hargajualan','gad.bakihargajualan','gad.bakipjm as gadaibakipjm','tebus.nilaimarhun','tebus.tagterima', 'tebus.teller','tebus.jenistebus','tebus.pinjaman','tebus.bakiupah','tebus.bakipjm','gad.norujukan','gad.nokp','tebus.jbg','tebus.ujrah','tebus.onepercent','gad.tagbaru') ->select('tebus.t_tebus', 'gad.t_gadai','gad.hargajualan','gad.bakihargajualan','gad.bakipjm as gadaibakipjm','tebus.nilaimarhun','tebus.tagterima', 'tebus.teller','tebus.jenistebus','tebus.pinjaman','tebus.bakiupah','tebus.bakipjm','gad.norujukan','gad.nokp','tebus.jbg','tebus.ujrah','tebus.onepercent','gad.tagbaru','tebus.diskaun_rebate')
->join('gadai as gad','gad.norujukan','=','tebus.norujukan') ->join('gadai as gad','gad.norujukan','=','tebus.norujukan')
// ->join('online_arrahn.customer as cust', function($join) // ->join('online_arrahn.customer as cust', function($join)
// { // {
@@ -232,7 +233,8 @@ class TebusController extends Controller
"nokp"=>$tebusData['nokp'], "nokp"=>$tebusData['nokp'],
"jbg"=>$tebusData['jbg'], "jbg"=>$tebusData['jbg'],
"ujrah"=>$trans['ujrah_rebet'], "ujrah"=>$trans['ujrah_rebet'],
"onepercent"=>$trans['onepercent_rebet'] "onepercent"=>$trans['onepercent_rebet'],
"diskaun_rebate"=>$tebusData['diskaun_rebate'],
]); ]);
} }
@@ -274,7 +276,8 @@ class TebusController extends Controller
'tebus.jbg', 'tebus.jbg',
'tebus.ujrah', 'tebus.ujrah',
'tebus.onepercent', 'tebus.onepercent',
'gad.tagbaru' 'gad.tagbaru',
'tebus.diskaun_rebate'
) )
->join('gadai as gad', 'gad.norujukan', '=', 'tebus.norujukan') ->join('gadai as gad', 'gad.norujukan', '=', 'tebus.norujukan')
->where('tebus.t_tebus', '>=', $request->mula) ->where('tebus.t_tebus', '>=', $request->mula)
@@ -310,7 +313,8 @@ class TebusController extends Controller
"jbg"=>$tebusData['jbg'], "jbg"=>$tebusData['jbg'],
"ujrah"=>$trans['ujrah_rebet'], "ujrah"=>$trans['ujrah_rebet'],
"onepercent"=>$trans['onepercent_rebet'], "onepercent"=>$trans['onepercent_rebet'],
"tagbaru"=>$tebusData['tagbaru'] "tagbaru"=>$tebusData['tagbaru'],
"diskaun_rebate"=>$tebusData['diskaun_rebate'],
]); ]);
} }
@@ -1672,6 +1676,53 @@ class TebusController extends Controller
return response($rebet); return response($rebet);
} }
public function RebetPromoCalculation($kodcaw, Request $request)
{
$kodcaw = $request->kodcaw ?: $kodcaw;
if (!Feature::enabled($kodcaw, Feature::REBET_ANNUR)) {
return response(0);
}
$cawangan = Cawangan::on('mysql7')->where('kodcaw', '=', $kodcaw)->first();
$rebet = Tebus::on($cawangan['mysql'])
->join('gadai as db2', 'tebus.norujukan', '=', 'db2.norujukan')
->where('tebus.t_tebus', '<=', $request->tarikh)
->where('db2.hargajualan', '>', '0')
->whereNotNull('db2.hargajualan')
->sum('diskaun_rebate');
return response($rebet);
}
public function PelarasanRebate($kodcaw, Request $request)
{
$kodcaw = $request->kodcaw ?: $kodcaw;
if (!Feature::enabled($kodcaw, Feature::REBET_ANNUR)) {
return response(0);
}
$cawangan = Cawangan::on('mysql7')
->where('kodcaw', $kodcaw)
->first();
$tarikhLaporan = Carbon::parse($request->tarikh)->toDateString();
$tarikhTamatPelarasan = '2026-09-02';
$tarikhAkhir = $tarikhLaporan > $tarikhTamatPelarasan
? $tarikhTamatPelarasan
: $tarikhLaporan;
$rebet = Tebus::on($cawangan['mysql'])
->join('gadai as db2', 'tebus.norujukan', '=', 'db2.norujukan')
->whereDate('tebus.t_tebus', '>=', '2025-05-13')
->whereDate('tebus.t_tebus', '<=', $tarikhAkhir)
->where('db2.hargajualan', '>', 0)
->whereDate('db2.t_gadai', '>', '2023-05-21')
->sum('tebus.diskaun_rebate');
return response($rebet);
}
public function RebetCalculationLejer($kodcaw,Request $request) public function RebetCalculationLejer($kodcaw,Request $request)
{ {
$cawangan = Cawangan::on('mysql7')->where('kodcaw','=',$request->kodcaw)->first(); $cawangan = Cawangan::on('mysql7')->where('kodcaw','=',$request->kodcaw)->first();
@@ -1687,6 +1738,26 @@ class TebusController extends Controller
return response($rebet); return response($rebet);
} }
public function RebetPromoCalculationLejer($kodcaw, Request $request)
{
$kodcaw = $request->kodcaw ?: $kodcaw;
if (!Feature::enabled($kodcaw, Feature::REBET_ANNUR)) {
return response(0);
}
$cawangan = Cawangan::on('mysql7')->where('kodcaw', '=', $kodcaw)->first();
$rebet = Tebus::on($cawangan['mysql'])
->join('gadai as db2', 'tebus.norujukan', '=', 'db2.norujukan')
->where('tebus.t_tebus', '>=', $request->mula)
->where('tebus.t_tebus', '<=', $request->hingga)
->where('db2.hargajualan', '>', '0')
->whereNotNull('db2.hargajualan')
->sum('diskaun_rebate');
return response($rebet);
}
public function getUpahLamaToday($kodcaw,$norujukan) public function getUpahLamaToday($kodcaw,$norujukan)
{ {
$current = Carbon::now(); $current = Carbon::now();
@@ -8,6 +8,7 @@ use App\Cawangan;
use App\Gadai; use App\Gadai;
use App\GlDetail; use App\GlDetail;
use App\Http\Controllers\TebusController as TebusController; use App\Http\Controllers\TebusController as TebusController;
use App\Lelong;
use App\Services\Loggers\OnlineTransactionLoggerService; use App\Services\Loggers\OnlineTransactionLoggerService;
use App\Services\OnePercentServices; use App\Services\OnePercentServices;
use App\Support\v2\Calculation; use App\Support\v2\Calculation;
@@ -767,8 +768,52 @@ class TransactionOnlineController extends Controller
return 'rejected'; return 'rejected';
} }
} }
public function CustomerInfoLelong(Request $request){
$cawangan_all = Cawangan::on('mysql7')->get();
$totalBakiLelong = 0;
$totalRugiLelong = 0;
foreach ($cawangan_all as $index => $cawangan) {
$gadai = Gadai::on($cawangan['mysql'])
->where('nokp', '=', $request->ic)
->where('sttebus','=','L')
->orderBy('t_gadai', 'desc')
->get()->toArray();
if (sizeof($gadai) != 0) {
foreach ($gadai as $gad) {
$bakilelong = Lelong::on($cawangan['mysql'])
->where(function($query) {
$query->whereNull('trkhtuntut')
->orWhere('trkhtuntut', '=', '');
})
->where('norujukan', '=' ,$gad['norujukan'])
->where('baki', '>=', 0)
->sum('baki');
$rugilelong = Lelong::on($cawangan['mysql'])
->where(function($query) {
$query->whereNull('trkhtuntut')
->orWhere('trkhtuntut', '=', '');
})
->where('norujukan', '=' ,$gad['norujukan'])
->where('baki','<',0)
->sum('baki');
$totalBakiLelong += $bakilelong;
$totalRugiLelong += $rugilelong;
}
}
}
return response()->json([
'success' => true,
'message' => 'Data retrieved successfully',
'data' => [
'bakilelong' => $totalBakiLelong,
'rugilelong' => $totalRugiLelong,
]
], 200);
}
} }
+60
View File
@@ -13,6 +13,7 @@ use App\Vault;
use Auth0\SDK\API\Management\Users; use Auth0\SDK\API\Management\Users;
use Illuminate\Http\Request; use Illuminate\Http\Request;
use Carbon\Carbon; use Carbon\Carbon;
use App\Services\StaffNotificationClient;
use Illuminate\Support\Facades\Log; use Illuminate\Support\Facades\Log;
class TunaiController extends Controller class TunaiController extends Controller
{ {
@@ -165,6 +166,21 @@ class TunaiController extends Controller
} }
public function getTunaiByTarikh(Request $request)
{
$cawangan = Cawangan::on('mysql7')->where('kodcaw','=',$request->kodcaw)->first();
$tunai = Tunai::on($cawangan['mysql'])
->where([['kodcaw','=',$request->kodcaw],
['tarikh','=',$request->tarikh],
['kodlaluan','=',$request->kodlaluan]
])
->orderBy('tarikh','desc')
->first();
return response()->json($tunai);
}
public function getTunaiPast($kodcaw,Request $request) public function getTunaiPast($kodcaw,Request $request)
{ {
@@ -461,10 +477,54 @@ class TunaiController extends Controller
$audit->updated_at = $current; $audit->updated_at = $current;
$audit->save(); $audit->save();
$this->notifyKhazanahAliranTunai($kodcaw, $request, $reqteller);
return response()->json($reqteller,200); return response()->json($reqteller,200);
} }
/**
* Inbox for PC/PPC at the branch. Failures must not block the request.
*
* @param string $kodcaw
* @param \Illuminate\Http\Request $request
* @param \App\RequestTeller $reqteller
* @return void
*/
protected function notifyKhazanahAliranTunai($kodcaw, Request $request, $reqteller)
{
try {
$cawangan = Cawangan::on('mysql7')->where('kodcaw', '=', $kodcaw)->first();
$namaCaw = $kodcaw;
if ($cawangan) {
$nama = trim((string) $cawangan->nama_cawangan);
if ($nama !== '') {
$namaCaw = $nama;
}
}
$modal = (float) $request->modal;
$serahan = (float) $request->serahan;
app(StaffNotificationClient::class)->notify([
'type' => 'aliran_tunai.pending_khazanah',
'cawangan' => $kodcaw,
'audience' => ['role' => 'pc'],
'data' => [
'request_no' => isset($reqteller->no) ? $reqteller->no : null,
'kodlaluan' => $request->kodlaluan,
'modal' => $modal,
'serahan' => $serahan,
'cawangan_nama' => $namaCaw,
],
]);
} catch (\Throwable $e) {
Log::warning('Aliran tunai khazanah notification failed: '.$e->getMessage(), [
'kodcaw' => $kodcaw,
'kodlaluan' => $request->kodlaluan,
]);
}
}
public function getTunaiSemalam($kodcaw) public function getTunaiSemalam($kodcaw)
{ {
$current = new Carbon(); $current = new Carbon();
+137 -80
View File
@@ -12,6 +12,7 @@ use App\GlDetail;
use App\imbangdugalama; use App\imbangdugalama;
use App\GlCode; use App\GlCode;
use App\Panjar; use App\Panjar;
use App\ModalOnline;
use Illuminate\Http\Request; use Illuminate\Http\Request;
use Carbon\Carbon; use Carbon\Carbon;
@@ -168,37 +169,64 @@ class VaultController extends Controller
return response()->json($updateVault, 200); return response()->json($updateVault, 200);
} }
public function updateVaultDeletePendahuluanSerahan($kodcaw, Request $request)
{
$current = Carbon::now();
$current = new Carbon();
$cawangan = Cawangan::on('mysql7')->where('kodcaw','=',$kodcaw)->first();
$vault=Vault::on($cawangan['mysql'])->where('kodcaw','=',$kodcaw)->where('tarikh','=',$current->toDateString())->orderby('tarikh','desc')->first(); public function updateVaultDeletePendahuluanSerahan($kodcaw, Request $request)
{
$current = new Carbon();
$bakiawal = $vault['bakiawal']; $cawangan = Cawangan::on('mysql7')->where('kodcaw', '=', $kodcaw)->first();
$keluar = $vault['keluar'];
$masuk = $vault['masuk'];
$bakiakhir = $vault['bakiakhir'];
$bakieod = $vault['bakieod'];
$pendahuluan = $vault['pendahuluan'];
$serahan = $vault['serahan'];
$totpanjaran = $vault['totpanjar'];
$glpend = GlDetail::on($cawangan['mysql'])->where('tarikh','=', $current->toDateString())->sum('pendahuluan'); if (!$cawangan) {
$glser = GlDetail::on($cawangan['mysql'])->where('tarikh','=', $current->toDateString())->where('teller','<>','ONLINE')->sum('serahan'); return response()->json(['message' => 'Cawangan tidak dijumpai'], 404);
}
$bakiakhir = $bakiawal - $keluar + $masuk + $glpend - $glser - $totpanjaran; $vault = Vault::on($cawangan['mysql'])
->where('kodcaw', '=', $kodcaw)
->where('tarikh', '=', $current->toDateString())
->first();
$updateVault=Vault::on($cawangan['mysql'])->where([['tarikh','=',$current->toDateString()],['kodcaw','=', $kodcaw]])->update(array( if (!$vault) {
'pendahuluan' => $glpend, return response()->json(['message' => 'Rekod vault hari ini tidak dijumpai'], 404);
'serahan' => $glser, }
'bakiakhir'=>$bakiakhir,
'bakieod'=>$bakiakhir
));
return response()->json($updateVault, 200); $bakiawal = $vault['bakiawal'];
} $keluar = $vault['keluar'];
$masuk = $vault['masuk'];
$totpanjaran = $vault['totpanjar'];
// Pendahuluan HQ (dari GL)
$glpend = GlDetail::on($cawangan['mysql'])
->where('tarikh', '=', $current->toDateString())
->sum('pendahuluan');
// Serahan (GL, exclude teller ONLINE)
$glser = GlDetail::on($cawangan['mysql'])
->where('tarikh', '=', $current->toDateString())
->where('teller', '<>', 'ONLINE')
->sum('serahan');
// Pendahuluan Online (had yang diluluskan hari ini)
$modalOnlineHad = ModalOnline::on($cawangan['mysql'])
->where('kodcaw', '=', $kodcaw)
->where('tarikh', '=', $current->toDateString())
->value('had') ?? 0;
// Gabungan pendahuluan HQ + pendahuluan online
$totalPendahuluan = $glpend + $modalOnlineHad;
$bakiakhir = $bakiawal - $keluar + $masuk + $totalPendahuluan - $glser - $totpanjaran;
$updateVault = Vault::on($cawangan['mysql'])
->where([['tarikh', '=', $current->toDateString()], ['kodcaw', '=', $kodcaw]])
->update([
'pendahuluan' => $totalPendahuluan,
'serahan' => $glser,
'bakiakhir' => $bakiakhir,
'bakieod' => $bakiakhir,
]);
return response()->json($updateVault, 200);
}
public function create($kodcaw,Request $request) public function create($kodcaw,Request $request)
{ {
@@ -400,12 +428,14 @@ class VaultController extends Controller
} }
$bakiakhirVault = $vault ? $vault['bakiakhir'] : 0;
if($total != 0) if($total != 0)
{ {
$totalbakiakhirtunai = $vault['bakiakhir'] + $total; $totalbakiakhirtunai = $bakiakhirVault + $total;
}else }else
{ {
$totalbakiakhirtunai = $vault['bakiakhir']; $totalbakiakhirtunai = $bakiakhirVault;
} }
return response()->json($totalbakiakhirtunai); return response()->json($totalbakiakhirtunai);
@@ -454,42 +484,49 @@ class VaultController extends Controller
return response()->json($arraytunaiditangan,200); return response()->json($arraytunaiditangan,200);
} }
public function laporanPetiBesi($kodcaw,$tarikh) public function laporanPetiBesi($kodcaw,$tarikh)
{ {
$current = Carbon::now(); $current = Carbon::now();
$current = new Carbon(); $current = new Carbon();
$cawangan = Cawangan::on('mysql7')->where('kodcaw','=',$kodcaw)->first(); $cawangan = Cawangan::on('mysql7')->where('kodcaw','=',$kodcaw)->first();
$vault=Vault::on($cawangan['mysql'])
->where('kodcaw','=',$kodcaw) if (!$cawangan) {
->where('tarikh','=', $tarikh) return response()->json(['error' => 'Cawangan tidak dijumpai'], 404);
->orderby('tarikh','desc')->first(); }
$vault = Vault::on($cawangan['mysql'])
->where('kodcaw','=',$kodcaw)
->where('tarikh','=', $tarikh)
->orderby('tarikh','desc')
->first();
if (!$vault) {
return response()->json(['error' => 'Tiada data pada tarikh tersebut'], 404);
}
return response()->json($vault); return response()->json($vault);
} }
public function CalculationPendahuluanSerahan($kodcaw,Request $request) public function CalculationPendahuluanSerahan($kodcaw,Request $request)
{ {
$cawangan = Cawangan::on('mysql7')->where('kodcaw','=',$kodcaw)->first(); $cawangan = Cawangan::on('mysql7')->where('kodcaw','=',$kodcaw)->first();
$serahanpkb = '1000/020'; $serahanpkb = '1000/020';
$serahanjmc = '1000/026'; $serahanjmc = '1000/026';
$pendahuluanpkb = '7000/102'; $pendahuluanpkb = '7000/102';
$pendahuluanjmc = '7000/106'; $pendahuluanjmc = '7000/106';
$serahankoperasi = '1000/090'; $serahankoperasi = '1000/090';
//Selepas Tawarruq //Selepas Tawarruq
$serahanpkbTawarruq = GlDetail::on($cawangan['mysql']) $serahanpkbTawarruq = GlDetail::on($cawangan['mysql'])
->where('ktacct','=',$serahanpkb) ->where('ktacct','=',$serahanpkb)
->where('tarikh','<=', $request->tarikh) ->where('tarikh','<=', $request->tarikh)
->where('tarikh','>','2021-03-24') ->where('tarikh','>','2021-03-24')
->sum('serahan'); ->sum('serahan');
//Sebelum Tawarruq
//Sebelum Tawarruq
if($kodcaw == 'KB2' || $kodcaw == 'WCY' || $kodcaw == '1STOP' || $kodcaw == 'ARM' || $kodcaw == 'APM' || $kodcaw == '010621' || $kodcaw == '010915' || $kodcaw == '020303') if($kodcaw == 'KB2' || $kodcaw == 'WCY' || $kodcaw == '1STOP' || $kodcaw == 'ARM' || $kodcaw == 'APM' || $kodcaw == '010621' || $kodcaw == '010915' || $kodcaw == '020303')
{ {
$serahanpkb = GlDetail::on($cawangan['mysql']) $serahanpkb = GlDetail::on($cawangan['mysql'])
@@ -536,47 +573,53 @@ class VaultController extends Controller
//Selepas Tawarruq //Selepas Tawarruq
$pendahuluanPKBtawarruq = GlDetail::on($cawangan['mysql']) $pendahuluanPKBtawarruq = GlDetail::on($cawangan['mysql'])
->where('ktacct','=',$pendahuluanpkb) ->where('ktacct','=',$pendahuluanpkb)
->where([['tarikh','<=', $request->tarikh],['tarikh','>','2021-03-24']]) ->where([['tarikh','<=', $request->tarikh],['tarikh','>','2021-03-24']])
->sum('pendahuluan'); ->sum('pendahuluan');
//Sebelum Tawarruq //Sebelum Tawarruq
$pendahuluanPKB = GlDetail::on($cawangan['mysql']) $pendahuluanPKB = GlDetail::on($cawangan['mysql'])
->where('ktacct','=',$pendahuluanpkb) ->where('ktacct','=',$pendahuluanpkb)
->where([['tarikh','<=', $request->tarikh],['tarikh','>','2013-12-31']]) ->where([['tarikh','<=', $request->tarikh],['tarikh','>','2013-12-31']])
->sum('amaun');
$pendahuluanJMC = GlDetail::on($cawangan['mysql'])
->where('ktacct','=','7000/106')
->where([['tarikh','<=', $request->tarikh],['tarikh','>','2013-12-31']])
->sum('amaun');
$pendahuluanpkblama = imbangdugalama::on($cawangan['mysql'])
->sum('pendahuluan_pkb');
$pendahuluanjmclama = imbangdugalama::on($cawangan['mysql'])
->sum('pendahuluan_jmc');
$total = $pendahuluanPKBtawarruq + $pendahuluanjmclama + $pendahuluanpkblama + $pendahuluanPKB + $pendahuluanJMC;
$pindahkekpkb = GlCode::on($cawangan['mysql'])
->where('glcode','=',$serahankoperasi)
->sum('amaun'); ->sum('amaun');
if($kodcaw == '011229') $pendahuluanJMC = GlDetail::on($cawangan['mysql'])
$totalserahan -= 0.10; ->where('ktacct','=','7000/106')
->where([['tarikh','<=', $request->tarikh],['tarikh','>','2013-12-31']])
->sum('amaun');
if($kodcaw == '011013') $pendahuluanpkblama = imbangdugalama::on($cawangan['mysql'])
$totalserahan += 641000; ->sum('pendahuluan_pkb');
$arraypend = ['pendahuluan' => $total,'serahan' => $totalserahan,'pindahkekpkb' => $pindahkekpkb]; $pendahuluanjmclama = imbangdugalama::on($cawangan['mysql'])
->sum('pendahuluan_jmc');
return response()->json($arraypend); //Pendahuluan Online (had)
} $modalOnlineHad = ModalOnline::on($cawangan['mysql'])
->where('kodcaw','=', $kodcaw)
->where('tarikh','=', $request->tarikh)
->value('had') ?? 0;
$total = $pendahuluanPKBtawarruq + $pendahuluanjmclama + $pendahuluanpkblama + $pendahuluanPKB + $pendahuluanJMC + $modalOnlineHad;
$pindahkekpkb = GlCode::on($cawangan['mysql'])
->where('glcode','=',$serahankoperasi)
->sum('amaun');
if($kodcaw == '011229')
$totalserahan -= 0.10;
if($kodcaw == '011013')
$totalserahan += 641000;
$arraypend = ['pendahuluan' => $total,'serahan' => $totalserahan,'pindahkekpkb' => $pindahkekpkb];
return response()->json($arraypend);
}
public function CalculationPendahuluanSerahanLejer($kodcaw,Request $request) public function CalculationPendahuluanSerahanLejer($kodcaw,Request $request)
@@ -722,5 +765,19 @@ class VaultController extends Controller
return response()->json($vault); return response()->json($vault);
} }
public function CalculationModalOnlineLejer($kodcaw, Request $request)
{
$cawangan = Cawangan::on('mysql7')->where('kodcaw','=',$kodcaw)->first();
$tarikh = $request->hingga;
$modal_online = ModalOnline::on($cawangan['mysql'])
->where('kodcaw', '=', $kodcaw)
->where('tarikh', '=', $tarikh)
->first();
return response()->json([
'had' => $modal_online ? floatval($modal_online->had) : 0,
]);
}
} }
+154
View File
@@ -5,8 +5,12 @@ namespace App\Http\Controllers;
use App\WTDDraft; use App\WTDDraft;
use App\TuntutBaki; use App\TuntutBaki;
use App\Cawangan; use App\Cawangan;
use App\Customer;
use Illuminate\Http\Request; use Illuminate\Http\Request;
use Carbon\Carbon; use Carbon\Carbon;
use App\Helper;
use App\SerahBaki;
use App\WTD;
use Illuminate\Support\Facades\Http; use Illuminate\Support\Facades\Http;
@@ -34,4 +38,154 @@ class WTDController extends Controller
return response()->json($tuntutbaki); return response()->json($tuntutbaki);
} }
public function getSummaryWtd(Request $request){
$startDate = $request->startDate ?? now()->startOfMonth()->toDateString();
$endDate = $request->endDate ?? now()->endOfMonth()->toDateString();
$active_dbs = Helper::getActiveCawanganDbConnection();
$cawangan = Cawangan::select('kodcaw', 'details_caw', 'mysql')
->whereIn('mysql', $active_dbs)
->get();
$responses = [];
foreach ($cawangan as $caw) {
$db = $caw->mysql;
$tuntutbaki = TuntutBaki::on($db)
->join('serahbaki', 'serahbaki.t_jual', '=', 'tuntutbaki.tarikh')
->join('gadai', 'gadai.norujukan', '=', 'tuntutbaki.norujukan')
->whereBetween('tuntutbaki.tarikh', [$startDate, $endDate])
->where('tuntutbaki.teller', 'DM')
->where('serahbaki.aktif', 1)
->selectRaw("
gadai.nokp as nokp,
tuntutbaki.norujukan as norujukan,
tuntutbaki.jumlah as jumlah,
serahbaki.batchno as batchno,
serahbaki.t_jual as t_jual,
serahbaki.t_htr_ag as t_htr_ag
")
->orderByRaw('CAST(serahbaki.batchno AS UNSIGNED)')
->orderBy('tuntutbaki.norujukan')
->get();
$nokps = $tuntutbaki
->pluck('nokp')
->filter() // elak null
//->unique()
->values();
$customers = Customer::on('mysql7')
->whereIn('kplama', $nokps)
->orWhereIn('kpbaru', $nokps)
->get()
->keyBy(function ($item) {
return $item->kpbaru ?: $item->kplama;
});
$wtd_det = [];
foreach ($tuntutbaki as $tuntut) {
$nokp = $tuntut->nokp;
$cust = $customers->get($nokp);
$wtd_det[] = [
"norujukan" => $tuntut->norujukan,
"nokp" => $nokp,
"jumlah" => (float) $tuntut->jumlah,
"batchno" => $tuntut->batchno,
"t_proses" => $tuntut->t_jual,
"t_htr_ag" => $tuntut->t_htr_ag,
"nama_cust" => $cust->nama ?? null,
];
}
$details = collect($wtd_det)
->values()
->all();
$responses[] = [
'kodcaw' => $caw->kodcaw,
'details_caw' => $caw->details_caw,
// WEB
'jumlah_surat' => count($details),
'sum_baki' => collect($details)->sum('jumlah'),
// EXCEL
'details' => $details,
];
}
return response()->json($responses);
}
public function getDebugWtd(Request $request){
$startDate = $request->startDate ?? now()->startOfMonth()->toDateString();
$endDate = $request->endDate ?? now()->endOfMonth()->toDateString();
$active_dbs = Helper::getActiveCawanganDbConnection();
$cawangan = Cawangan::select('kodcaw', 'details_caw', 'mysql')
->whereIn('mysql', $active_dbs)
->get();
$responses = [];
foreach ($cawangan as $caw) {
$db = $caw->mysql;
$serahbaki = SerahBaki::on($db)
->whereBetween('t_jual', [$startDate, $endDate])
->where('aktif', 1)
//->selectRaw("baki as serahb")
->sum('baki');;
//->get();
$tuntutbaki = TuntutBaki::on($db)
->whereBetween('tarikh', [$startDate, $endDate])
->where('teller', 'DM')
//->selectRaw("jumlah as tuntutb")
->sum('jumlah');
//->get();
$twtd = WTD::on($db)
->whereBetween('tarikh', [$startDate, $endDate])
//->selectRaw("wtd as twtd")
->sum('wtd');
//->get();
$wtd_det = [];
$wtd_det[] = [
"serahb" => $serahbaki,
"tuntutb" => $tuntutbaki,
"twtd" => $twtd,
];
$details = collect($wtd_det)
->values()
->all();
//dd($details);
$responses[] = [
'kodcaw' => $caw->kodcaw,
'details_caw' => $caw->details_caw,
//collect($details)->sum('jumlah'),
// WEB
'serahb' => collect($details)->sum('serahb'),
'tuntutb' => collect($details)->sum('tuntutb'),
'twtd' => collect($details)->sum('twtd'),
//'debugwtd' => $details,
];
}
return response()->json($responses);
}
} }
@@ -0,0 +1,122 @@
<?php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Log;
/**
* Meta WhatsApp Cloud webhook: verify challenge + acknowledge events.
* Sufficient for production onboarding; delivery statuses are logged only.
*/
class WhatsappWebhookController extends Controller
{
/**
* GET /api/whatsapp/webhook
* Meta sends hub.mode, hub.verify_token, hub.challenge.
*/
public function verify(Request $request)
{
$mode = $request->query('hub_mode', $request->query('hub.mode'));
$token = $request->query('hub_verify_token', $request->query('hub.verify_token'));
$challenge = $request->query('hub_challenge', $request->query('hub.challenge'));
$expected = (string) config('whatsapp.verify_token');
if ($mode === 'subscribe' && $expected !== '' && hash_equals($expected, (string) $token)) {
Log::info('WhatsApp webhook verified');
return response((string) $challenge, 200)
->header('Content-Type', 'text/plain');
}
Log::warning('WhatsApp webhook verify failed', [
'mode' => $mode,
'token_match' => $expected !== '' && hash_equals($expected, (string) $token),
]);
return response('Forbidden', 403);
}
/**
* POST /api/whatsapp/webhook
* Acknowledge quickly; optionally check X-Hub-Signature-256 when app secret is set.
*/
public function handle(Request $request)
{
$raw = $request->getContent();
if (!$this->signatureOk($request, $raw)) {
Log::warning('WhatsApp webhook invalid signature');
return response('Invalid signature', 403);
}
$payload = json_decode($raw, true);
if (!is_array($payload)) {
return response('OK', 200);
}
try {
$this->logEvents($payload);
} catch (\Throwable $e) {
Log::error('WhatsApp webhook log failed: ' . $e->getMessage());
}
return response('OK', 200);
}
protected function signatureOk(Request $request, $raw)
{
$secret = trim((string) config('whatsapp.app_secret'));
if ($secret === '') {
return true;
}
$header = (string) $request->header('X-Hub-Signature-256', '');
if ($header === '' || strpos($header, 'sha256=') !== 0) {
return false;
}
$expected = 'sha256=' . hash_hmac('sha256', $raw, $secret);
return hash_equals($expected, $header);
}
protected function logEvents(array $payload)
{
$entries = $payload['entry'] ?? [];
if (!is_array($entries)) {
return;
}
foreach ($entries as $entry) {
$changes = $entry['changes'] ?? [];
if (!is_array($changes)) {
continue;
}
foreach ($changes as $change) {
$value = $change['value'] ?? [];
if (!is_array($value)) {
continue;
}
foreach ($value['statuses'] ?? [] as $status) {
Log::info('WhatsApp status', [
'id' => $status['id'] ?? null,
'status' => $status['status'] ?? null,
'recipient' => $status['recipient_id'] ?? null,
'errors' => $status['errors'] ?? null,
]);
}
foreach ($value['messages'] ?? [] as $message) {
Log::info('WhatsApp inbound', [
'from' => $message['from'] ?? null,
'type' => $message['type'] ?? null,
'id' => $message['id'] ?? null,
]);
}
}
}
}
}
+32
View File
@@ -0,0 +1,32 @@
<?php
namespace App\Http\Middleware;
use Closure;
class LogViewerPassword
{
public function handle($request, Closure $next)
{
$passwordHash = config('logviewer.password');
if (!is_string($passwordHash) || $passwordHash === '') {
return response('Akses log belum dikonfigurasi.', 503)
->header('Cache-Control', 'no-store');
}
$provided = $request->getPassword();
if ($request->getUser() !== 'logviewer' || !is_string($provided) ||
!password_verify($provided, $passwordHash)) {
return response('Kata laluan diperlukan untuk mengakses log.', 401, [
'WWW-Authenticate' => 'Basic realm="Log Viewer", charset="UTF-8"',
'Cache-Control' => 'no-store',
]);
}
$response = $next($request);
$response->headers->set('Cache-Control', 'no-store');
return $response;
}
}
+153
View File
@@ -0,0 +1,153 @@
<?php
namespace App\Jobs;
use App\BlastWasap;
use App\Customer;
use App\Services\Whatsapp\WhatsappCloudClient;
use Carbon\Carbon;
use Illuminate\Support\Facades\Log;
class WhatsappPembiayaanOnlinePaid extends Job
{
public $kodcaw;
public $cawName;
public $nokp;
public $norujukan;
public $pinjaman;
public $namaBank;
public $noakaun;
public $tarikhBayaran;
public $noRujukanBayaran;
public function __construct(array $data)
{
$this->kodcaw = $data['kodcaw'] ?? null;
$this->cawName = $data['caw_name'] ?? null;
$this->nokp = $data['nokp'] ?? null;
$this->norujukan = $data['norujukan'] ?? null;
$this->pinjaman = $data['pinjaman'] ?? null;
$this->namaBank = $data['nama_bank'] ?? null;
$this->noakaun = $data['noakaun'] ?? null;
$this->tarikhBayaran = $data['tarikh_bayaran'] ?? null;
$this->noRujukanBayaran = $data['no_rujukan_bayaran'] ?? null;
}
public function handle()
{
$client = new WhatsappCloudClient();
$now = Carbon::now();
if (!$client->isConfigured()) {
Log::warning('WhatsApp Cloud skipped: token or phone_number_id missing', [
'norujukan' => $this->norujukan,
]);
return;
}
$customer = Customer::on('mysql7')
->where(function ($q) {
$q->where('kpbaru', $this->nokp)->orWhere('kplama', $this->nokp);
})
->first();
$storedPhone = $customer ? ($customer->telefon ?: $customer->telefon2) : null;
$to = $client->normalizeMsisdn($storedPhone);
if (!config('whatsapp.whatsapp_cloud_enabled')) {
$admin = $client->normalizeMsisdn(env('ADMIN_PHONE_NUMBER'));
if (!$admin) {
Log::warning('WhatsApp Cloud skipped: ADMIN_PHONE_NUMBER required when WHATSAPP_ENABLED is false', [
'norujukan' => $this->norujukan,
]);
$this->logBlast($now, $storedPhone, 'skipped: ADMIN_PHONE_NUMBER empty');
return;
}
$to = $admin;
}
if (!$to) {
Log::warning('WhatsApp Cloud skipped: no phone', [
'nokp' => $this->nokp,
'norujukan' => $this->norujukan,
]);
$this->logBlast($now, $storedPhone, 'skipped: no phone');
return;
}
$template = config('whatsapp.template', 'hello_world');
$lang = config('whatsapp.template_lang', 'en_US');
$bodyParams = $this->isHelloWorld($template) ? [] : $this->bodyParams();
try {
$response = $client->sendTemplate($to, $template, $lang, $bodyParams);
$this->logBlast($now, $to, $response->body());
} catch (\Throwable $e) {
Log::error('WhatsappPembiayaanOnlinePaid failed: ' . $e->getMessage(), [
'norujukan' => $this->norujukan,
]);
$this->logBlast($now, $to, 'exception: ' . $e->getMessage());
}
}
protected function isHelloWorld($template)
{
return strtolower((string) $template) === 'hello_world';
}
/**
* Matches Meta template pembiayaan_online_paid (ms):
* AR-RAHN KoPKB: Pembiayaan bagi No. SAG *{{1}}* sebanyak *RM{{2}}*
* telah berjaya dikreditkan ke akaun *{{3}}* berakhir *{{4}}* pada *{{5}}*.
* Rujukan: *{{6}}*
*
* {{1}} SAG, {{2}} amaun, {{3}} nama bank/akaun, {{4}} 4 digit akhir, {{5}} tarikh, {{6}} rujukan bayaran
*
* @return array<int,string>
*/
protected function bodyParams()
{
$bank = trim((string) $this->namaBank);
$tail = $this->accountTail($this->noakaun);
$tarikh = $this->tarikhBayaran
? Carbon::parse($this->tarikhBayaran)->format('d/m/Y')
: Carbon::now()->format('d/m/Y');
return [
$this->norujukan ?: '-',
number_format((float) $this->pinjaman, 2, '.', ''),
$bank !== '' ? $bank : '-',
$tail !== '' ? $tail : '-',
$tarikh,
$this->noRujukanBayaran ?: '-',
];
}
protected function accountTail($noakaun)
{
$digits = preg_replace('/\D+/', '', (string) $noakaun);
if ($digits === '') {
return '';
}
return substr($digits, -4);
}
protected function logBlast($now, $telefon, $status)
{
try {
$log = new BlastWasap();
$log->kodcaw = $this->kodcaw;
$log->nokp = $this->nokp;
$log->notelefon = $telefon;
$log->norujukan = $this->norujukan;
$log->status = is_string($status) ? $status : json_encode($status);
$log->created_at = $now;
$log->updated_at = $now;
$log->save();
} catch (\Throwable $e) {
Log::error('log_blast_wasap save failed: ' . $e->getMessage());
}
}
}
+18
View File
@@ -0,0 +1,18 @@
<?php
namespace App;
use Illuminate\Database\Eloquent\Model;
class KadarRebet extends Model
{
protected $table = 'kadar_rebet';
protected $connection = 'mysql7';
public $timestamps = false;
protected $fillable = [
'pembiayaan_min',
'pembiayaan_max',
'kadarrebet',
];
}
+40
View File
@@ -0,0 +1,40 @@
<?php
namespace App;
use Illuminate\Database\Eloquent\Model;
class MaxMutuEmas extends Model
{
protected $table = 'max_mutuemas';
protected $primaryKey = 'recno';
public $timestamps = false;
/**
* The attributes that are mass assignable.
*
* @var array
*/
protected $fillable = [
'recno', 'karat', 'keterangan', 'teller', 'pc', 'operasi', 'tarikhupdate'
];
/**
* The attributes that should be cast to native types.
*
* @var array
*/
protected $casts = [
'teller' => 'decimal:2',
'pc' => 'decimal:2',
'operasi' => 'decimal:2',
'tarikhupdate' => 'datetime',
];
/**
* The attributes excluded from the model's JSON form.
*
* @var array
*/
// protected $hidden = [];
}
+23
View File
@@ -0,0 +1,23 @@
<?php
namespace App;
use Illuminate\Database\Eloquent\Model;
class ModalOnline extends Model
{
protected $table = 'modal_online';
protected $fillable = [
'tarikh',
'kodcaw',
'had',
'digunakan',
'baki',
'tambah',
'kurang',
'ditutup',
'ditutup_oleh',
'ditutup_at',
];
}
+13
View File
@@ -4,6 +4,7 @@ namespace App;
use Illuminate\Database\Eloquent\Model; use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsTo; use Illuminate\Database\Eloquent\Relations\BelongsTo;
use Illuminate\Database\Eloquent\Relations\HasOne;
use App\Audit; use App\Audit;
use Illuminate\Support\Carbon; use Illuminate\Support\Carbon;
@@ -21,6 +22,7 @@ class Palsu extends Model
protected $fillable = [ protected $fillable = [
'recno', 'recno',
'kodcaw', 'kodcaw',
'tarikh',
'norujukan', 'norujukan',
'teller', 'teller',
'nota', 'nota',
@@ -30,6 +32,7 @@ class Palsu extends Model
'untungonepercent', 'untungonepercent',
'untungcajlain', 'untungcajlain',
'pembiayaan', 'pembiayaan',
'status',
]; ];
// public static function boot() // public static function boot()
@@ -87,4 +90,14 @@ class Palsu extends Model
// { // {
// return $this->belongsTo(Daerah::class, 'koddaerah', 'koddaerah'); // return $this->belongsTo(Daerah::class, 'koddaerah', 'koddaerah');
// } // }
public function tebus(): HasOne
{
return $this->hasOne(Tebus::class, 'norujukan', 'norujukan');
}
public function gadai(): HasOne
{
return $this->hasOne(Gadai::class, 'norujukan', 'norujukan');
}
} }
+35
View File
@@ -0,0 +1,35 @@
<?php
namespace App;
use Illuminate\Database\Eloquent\Model;
class Pampasan extends Model
{
protected $table = 'pampasan';
public $timestamps = true;
/**
* The attributes that are mass assignable.
*
* @var array
*/
protected $fillable = [
'id',
'norujukan',
'baucerno',
'kodcaw',
'jumlah_pampasan',
'denominasi',
'teller',
'nota',
'agreement_printed_at',
];
/**
* The attributes excluded from the model's JSON form.
*
* @var array
*/
// protected $hidden = [];
}
+41
View File
@@ -0,0 +1,41 @@
<?php
namespace App;
use Illuminate\Database\Eloquent\Model;
class PembiayaanOnline extends Model
{
protected $table = 'pembiayaan_online';
protected $fillable = [
'norujukan',
'nokp',
'nopelanggan',
'nama_pelanggan',
'kodcaw',
'pinjaman',
'kodbank',
'nama_bank',
'noakaun',
'nama_akaun',
'bukti_akaun_file_id',
'borang_file_id',
'status',
'reject_reason',
'rejected_by',
'rejected_at',
'batch_id',
'bukti_file_id',
'no_rujukan_bayaran',
'tarikh_bayaran',
'paid_at',
'created_by',
'pc_submitted_by',
'pc_verified_by',
'pc_verified_at',
'ops_by',
'nota',
'blast_sent',
];
}
+21
View File
@@ -0,0 +1,21 @@
<?php
namespace App;
use Illuminate\Database\Eloquent\Model;
class RequestModalOnline extends Model
{
protected $table = 'request_modal_online';
protected $connection = 'mysql7';
protected $fillable = [
'kodcaw',
'tarikh',
'amaun',
'dimohon_oleh',
'status',
'diluluskan_oleh',
'nota',
];
}
@@ -0,0 +1,165 @@
<?php
namespace App\Services\Miscellaneous;
use App\Http\Controllers\Controller;
use App\Cawangan;
use App\Gadai;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\DB;
use App\Services\Reports\GadaianService as ReportGadaianService;
use App\Helper;
use App\Tebus;
use Illuminate\Support\Carbon;
class StatistikService
{
protected $kodcaw;
protected $mysql;
protected $mula;
protected $akhir;
public function __construct($kodcaw,$mula,$akhir)
{
$this->kodcaw = $kodcaw;
$this->mysql = Cawangan::on('mysql7')->where('kodcaw', $kodcaw)->value('mysql');
$this->mula = $mula;
$this->akhir = $akhir;
}
public function LaporanStatistik($gadai) : array
{
$reportPembiayaan = $this->countPawnByType($gadai);
$reportLoanAmount = $this->countPawnByLoan($gadai);
$reportMarhunValue = $this->countMarhunByValue($gadai);
$reportMarhunMargin = $this->countMarhunByMargin($gadai);
$reportCustomerJob = $this->countCustomerByJob($gadai);
$reportCustomerRace = $this->countCustomerByRace($gadai);
// dd($reportCustomerRace);
return [
'reportPembiayaan' => $reportPembiayaan,
'reportLoanAmount' => $reportLoanAmount,
'reportMarhunValue' => $reportMarhunValue,
'reportMarhunMargin' => $reportMarhunMargin,
'reportCustomerJob' => $reportCustomerJob,
'reportCustomerRace' => $reportCustomerRace,
];
}
private function countPawnByType($gadai)
{
$pembiayaanbaru = Tebus::on($this->mysql)
->join('gadai as g1', 'tebus.norujukan', '=', 'g1.norujukan')
->join('gadai as g2', function ($join) {
$join->on('g2.nokp', '=', 'g1.nokp')
->on('g2.t_gadai', '=', 'tebus.t_tebus')
->whereRaw('ABS(g2.berat - g1.berat) <= 0.02')
->whereColumn('g2.norujukan', '!=', 'g1.norujukan');
})
->whereBetween('tebus.t_tebus', [$this->mula, $this->akhir])
->groupBy('tebus.norujukan')
->selectRaw("
tebus.norujukan as norujukan_tebus,
MAX(g2.norujukan) as norujukanpembiayaansemula,
MAX(g1.taglel) as taglel_lama
")
->get()
->toArray();
$pembiayaanbaruNorujukan = array_column($pembiayaanbaru, 'norujukanpembiayaansemula');
$filteredNorujukanLelongan = array_column(
array_filter($pembiayaanbaru, function ($item) {
return $item['taglel_lama'] == 1;
}),
'norujukanpembiayaansemula'
);
$filteredPSNorujukan = array_column(
array_filter($pembiayaanbaru, function ($item) {
return $item['taglel_lama'] == 0;
}),
'norujukanpembiayaansemula'
);
$pembiayaanbaru = $gadai->whereIn('norujukan', $filteredPSNorujukan)->count();
$pembiayaansemula = $gadai->whereNotIn('norujukan', $pembiayaanbaruNorujukan)->count();
$lelongan = $gadai->whereIn('norujukan', $filteredNorujukanLelongan)->count();
return [
'pembiayaanbaru' => $pembiayaanbaru,
'pembiayaansemula' => $pembiayaansemula,
'lelongan' => $lelongan
];
}
private function countPawnByLoan($gadai)
{
return collect($gadai)->countBy(function ($item) {
$loan = $item['pinjaman'];
if ($loan <= 400.99) return '< 400.99';
if ($loan >= 401 && $loan <= 2000) return '401 - 2000';
if ($loan >= 2001 && $loan <= 24999) return '2001 - 2499';
if ($loan >= 2500) return '>= 2500';
if ($loan > 101000) return '>101000';
})->toArray();
}
private function countMarhunByValue($gadai)
{
return collect($gadai)->countBy(function ($item) {
$nilaimarhun = $item['nilaimarhun'];
if ($nilaimarhun <= 400.99) return '< 1-400';
if ($nilaimarhun >= 401 && $nilaimarhun <= 2000) return '401-2000';
if ($nilaimarhun > 2001) return '> 2001';
})->toArray();
}
private function countMarhunByMargin($gadai)
{
return collect($gadai)->countBy(function ($item) {
$margin= $item['percentpinj'];
if ($margin >= 10 && $margin <= 40.99) return '10-40.99';
if ($margin >= 41 && $margin <= 60.99) return '41-60.99';
if ($margin >= 61 && $margin <= 80) return '> 61-80';
})->toArray();
}
private function countCustomerByJob($gadai)
{
$jobMap = [
1 => 'Peniaga',
2 => 'Pekerja Swasta',
3 => 'Pekerja Kerajaan',
4 => 'Bekerja Sendiri',
5 => 'Suri Rumah',
6 => 'Lain-lain',
];
return collect($gadai)->countBy(function ($item) use ($jobMap) {
$kodkerja = floatval($item['kodkerja']);
return $jobMap[$kodkerja] ?? 'Lain-lain';
})->toArray();
}
private function countCustomerByRace($gadai){
$raceMap = [
'M' => 'Melayu',
'C' => 'Cina',
'I' => 'India',
'L' => 'Lain-lain',
];
return collect($gadai)->countBy(function ($item) use ($raceMap) {
return $raceMap[$item['bangsa']] ?? 'Lain-lain';
})->toArray();
}
}
@@ -0,0 +1,918 @@
<?php
namespace App\Services\PembiayaanOnline;
use App\Cawangan;
use App\Feature;
use App\ModalOnline;
use App\RequestModalOnline;
use App\Services\StaffNotificationClient;
use Carbon\Carbon;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Log;
class ModalOnlineService
{
/**
* @return array{ok:bool,status:int,payload:mixed,mysql?:string}
*/
public function resolveMysql($kodcaw)
{
$cawangan = Cawangan::on('mysql7')->where('kodcaw', '=', $kodcaw)->first();
if (!$cawangan) {
return [
'ok' => false,
'status' => 404,
'payload' => ['message' => 'Cawangan tidak dijumpai'],
];
}
return [
'ok' => true,
'status' => 200,
'payload' => null,
'mysql' => $cawangan['mysql'],
];
}
protected function todayDate()
{
return Carbon::now()->toDateString();
}
protected function findPending($kodcaw)
{
return RequestModalOnline::on('mysql7')
->where('kodcaw', $kodcaw)
->where('status', 'PENDING')
->first();
}
protected function pendingPayload($pending)
{
return $pending ? $pending->toArray() : null;
}
protected function missingSnapshot($kodcaw, $tarikh, $pending = null)
{
return [
'tarikh' => $tarikh,
'kodcaw' => $kodcaw,
'had' => 0.00,
'digunakan' => 0.00,
'baki' => 0.00,
'tambah' => 0.00,
'kurang' => 0.00,
'ditutup' => 0,
'missing' => true,
'pending_request' => $this->pendingPayload($pending),
];
}
protected function recalcBaki($modal)
{
$modal->baki = round(
(float) $modal->had + (float) $modal->tambah - (float) $modal->kurang - (float) $modal->digunakan,
2
);
}
/**
* Get today's modal_online row. Does not create — PC must request had from Operasi.
*
* @return array{ok:bool,status:int,payload:mixed}
*/
public function get($kodcaw)
{
$resolved = $this->resolveMysql($kodcaw);
if (!$resolved['ok']) {
return $resolved;
}
$mysql = $resolved['mysql'];
$tarikh = $this->todayDate();
$pending = $this->findPending($kodcaw);
$modal = ModalOnline::on($mysql)
->where('kodcaw', $kodcaw)
->where('tarikh', $tarikh)
->first();
if (!$modal) {
return [
'ok' => true,
'status' => 200,
'payload' => $this->missingSnapshot($kodcaw, $tarikh, $pending),
];
}
$payload = $modal->toArray();
$payload['missing'] = false;
$payload['pending_request'] = $this->pendingPayload($pending);
return [
'ok' => true,
'status' => 200,
'payload' => $payload,
];
}
/**
* @deprecated Use get(). Kept so existing callers do not auto-seed RM100k.
*/
public function getOrCreate($kodcaw)
{
return $this->get($kodcaw);
}
/**
* Reserve amount inside an existing branch DB connection (caller may wrap in transaction).
*
* @return array{ok:bool,status:int,payload:mixed}
*/
public function reserveAmountOnConnection($mysql, $kodcaw, $amaun, $tarikh = null)
{
$amaun = round((float) $amaun, 2);
if ($amaun <= 0) {
return [
'ok' => false,
'status' => 422,
'payload' => ['message' => 'Amaun tidak sah'],
];
}
$tarikh = $tarikh ?: Carbon::now()->toDateString();
$modal = ModalOnline::on($mysql)
->where('kodcaw', $kodcaw)
->where('tarikh', $tarikh)
->lockForUpdate()
->first();
if (!$modal) {
return [
'ok' => false,
'status' => 422,
'payload' => [
'message' => 'Modal online belum diwujudkan. Sila mohon had daripada Operasi terlebih dahulu.',
'missing' => true,
],
];
}
if ((int) ($modal->ditutup ?? 0) === 1) {
return [
'ok' => false,
'status' => 422,
'payload' => [
'message' => 'Modal online hari ini sudah ditutup (EOD)',
'modal_online' => $modal,
],
];
}
if ((float) $modal->baki < $amaun) {
return [
'ok' => false,
'status' => 422,
'payload' => [
'message' => 'Baki modal online tidak mencukupi',
'baki' => (float) $modal->baki,
'amaun' => $amaun,
],
];
}
$modal->digunakan = round((float) $modal->digunakan + $amaun, 2);
$modal->baki = round(
(float) $modal->had + (float) $modal->tambah - (float) $modal->kurang - (float) $modal->digunakan,
2
);
$modal->save();
return [
'ok' => true,
'status' => 200,
'payload' => $modal,
];
}
/**
* Reserve amount from today's online float (transactional).
*
* @return array{ok:bool,status:int,payload:mixed}
*/
public function reserve($kodcaw, $amaun)
{
$resolved = $this->resolveMysql($kodcaw);
if (!$resolved['ok']) {
return $resolved;
}
if (!Feature::enabled($kodcaw, Feature::PEMBIAYAAN_ONLINE)) {
return Feature::denied('Pembiayaan online tidak diaktifkan untuk cawangan ini');
}
$mysql = $resolved['mysql'];
$amaun = round((float) $amaun, 2);
if ($amaun <= 0) {
return [
'ok' => false,
'status' => 422,
'payload' => ['message' => 'Amaun tidak sah'],
];
}
try {
return DB::connection($mysql)->transaction(function () use ($mysql, $kodcaw, $amaun) {
return $this->reserveAmountOnConnection($mysql, $kodcaw, $amaun);
});
} catch (\Throwable $e) {
Log::error('ModalOnline reserve failed: ' . $e->getMessage());
return [
'ok' => false,
'status' => 500,
'payload' => ['message' => 'Gagal reserve modal online'],
];
}
}
/**
* Had is no longer auto-seeded. Returns how many branches already have a row today.
*
* @return array{ok:bool,status:int,payload:mixed}
*/
public function initiate($zone = 'all')
{
$current = $this->todayDate();
if ($zone == 'all') {
$cawanganAll = Cawangan::on('mysql7')->get();
} else {
$cawanganAll = Cawangan::on('mysql7')->where('zone', $zone)->get();
}
$existing = 0;
$missing = 0;
foreach ($cawanganAll as $cawangan) {
try {
$exists = ModalOnline::on($cawangan['mysql'])
->where('kodcaw', $cawangan['kodcaw'])
->where('tarikh', $current)
->exists();
if ($exists) {
$existing++;
} else {
$missing++;
}
} catch (\Throwable $e) {
Log::warning('initiate modal_online skip ' . $cawangan['kodcaw'] . ': ' . $e->getMessage());
}
}
return [
'ok' => true,
'status' => 200,
'payload' => [
'tarikh' => $current,
'created' => 0,
'existing' => $existing,
'missing' => $missing,
'message' => 'Modal online tidak di-initiate automatik. PC perlu mohon had daripada Operasi.',
],
];
}
/**
* PC request opening had (or extra top-up) from Operasi.
*
* @return array{ok:bool,status:int,payload:mixed}
*/
public function requestTopUp($kodcaw, $amaun, $dimohonOleh, $nota = null)
{
$resolved = $this->resolveMysql($kodcaw);
if (!$resolved['ok']) {
return $resolved;
}
$mysql = $resolved['mysql'];
if (!Feature::enabled($kodcaw, Feature::PEMBIAYAAN_ONLINE)) {
return Feature::denied('Pembiayaan online tidak diaktifkan untuk cawangan ini');
}
$amaun = round((float) $amaun, 2);
$dimohonOleh = trim((string) $dimohonOleh);
if ($amaun <= 0) {
return [
'ok' => false,
'status' => 422,
'payload' => ['message' => 'Amaun tidak sah'],
];
}
if ($dimohonOleh === '') {
return [
'ok' => false,
'status' => 422,
'payload' => ['message' => 'dimohon_oleh diperlukan'],
];
}
$tarikh = $this->todayDate();
$pending = $this->findPending($kodcaw);
if ($pending) {
return [
'ok' => false,
'status' => 409,
'payload' => [
'message' => 'Masih ada permohonan modal online PENDING untuk cawangan ini',
'request' => $pending,
],
];
}
$modal = ModalOnline::on($mysql)
->where('kodcaw', $kodcaw)
->where('tarikh', $tarikh)
->first();
if ($modal && (int) ($modal->ditutup ?? 0) === 1) {
return [
'ok' => false,
'status' => 422,
'payload' => [
'message' => 'Modal online hari ini sudah ditutup (EOD). Tidak boleh mohon.',
'modal_online' => $modal,
],
];
}
$jenis = $modal ? 'TOPUP' : 'HAD';
$request = RequestModalOnline::on('mysql7')->create([
'kodcaw' => $kodcaw,
'tarikh' => $tarikh,
'amaun' => $amaun,
'dimohon_oleh' => $dimohonOleh,
'status' => 'PENDING',
'nota' => $nota,
]);
$this->notifyOperasiModalRequest($kodcaw, $request, $jenis);
return [
'ok' => true,
'status' => 201,
'payload' => [
'request' => $request,
'jenis' => $jenis,
'modal_online' => $modal ?: $this->missingSnapshot($kodcaw, $tarikh, $request),
],
];
}
/**
* Inbox for all operasi staff. Failures must not block the request.
*
* @param string $kodcaw
* @param \App\RequestModalOnline $request
* @param string $jenis
* @return void
*/
protected function notifyOperasiModalRequest($kodcaw, $request, $jenis)
{
try {
app(StaffNotificationClient::class)->notify([
'type' => 'modal_online.pending_operasi',
'cawangan' => $kodcaw,
'audience' => ['role' => 'operasi'],
'data' => [
'request_id' => $request->id,
'amaun' => (float) $request->amaun,
'dimohon_oleh' => $request->dimohon_oleh,
'jenis' => $jenis,
'nota' => $request->nota,
'cawangan_nama' => $this->cawanganNama($kodcaw),
],
]);
} catch (\Throwable $e) {
Log::warning('Operasi modal-online notification failed: '.$e->getMessage(), [
'kodcaw' => $kodcaw,
'request_id' => $request->id,
]);
}
}
/**
* @param string $kodcaw
* @return string
*/
protected function cawanganNama($kodcaw)
{
$cawangan = Cawangan::on('mysql7')->where('kodcaw', '=', $kodcaw)->first();
if (!$cawangan) {
return $kodcaw;
}
$nama = trim((string) $cawangan->nama_cawangan);
return $nama !== '' ? $nama : $kodcaw;
}
/**
* List top-up requests.
* For PC: pass kodcaw. For Operasi: omit kodcaw (all branches).
*
* @return array{ok:bool,status:int,payload:mixed}
*/
public function listTopUpRequests($kodcaw = null, $status = null, $tarikh = null)
{
$query = RequestModalOnline::on('mysql7')->newQuery();
if ($kodcaw) {
$query->where('kodcaw', $kodcaw);
}
if ($status) {
$query->where('status', $status);
}
if ($tarikh) {
$query->where('tarikh', $tarikh);
}
$rows = $query->orderBy('id', 'desc')->get();
$cawMap = [];
if (!$kodcaw) {
foreach (Cawangan::on('mysql7')->get() as $caw) {
$cawMap[$caw->kodcaw] = $caw->nama_cawangan;
}
}
$data = [];
foreach ($rows as $row) {
$item = $row->toArray();
if (!$kodcaw) {
$item['cawangan_nama'] = $cawMap[$row->kodcaw] ?? null;
}
$data[] = $item;
}
return [
'ok' => true,
'status' => 200,
'payload' => [
'bilangan' => count($data),
'data' => $data,
],
];
}
/**
* Operasi approve: first request of the day sets had; later requests add tambah.
* Optional $amaunOverride lets operasi lulus a different amount than dimohon.
*
* @return array{ok:bool,status:int,payload:mixed}
*/
public function approveTopUp($requestId, $diluluskanOleh, $nota = null, $expectedKodcaw = null, $amaunOverride = null)
{
$diluluskanOleh = trim((string) $diluluskanOleh);
if ($diluluskanOleh === '') {
return [
'ok' => false,
'status' => 422,
'payload' => ['message' => 'diluluskan_oleh diperlukan'],
];
}
$req = RequestModalOnline::on('mysql7')->where('id', $requestId)->first();
if (!$req) {
return [
'ok' => false,
'status' => 404,
'payload' => ['message' => 'Permohonan tidak dijumpai'],
];
}
if ($expectedKodcaw && $req->kodcaw !== $expectedKodcaw) {
return [
'ok' => false,
'status' => 404,
'payload' => ['message' => 'Permohonan tidak dijumpai'],
];
}
if ($req->status !== 'PENDING') {
return [
'ok' => false,
'status' => 422,
'payload' => [
'message' => 'Hanya permohonan PENDING boleh diluluskan',
'status' => $req->status,
],
];
}
$kodcaw = $req->kodcaw;
$resolved = $this->resolveMysql($kodcaw);
if (!$resolved['ok']) {
return $resolved;
}
$mysql = $resolved['mysql'];
$amaunDimohon = round((float) $req->amaun, 2);
$amaun = $amaunDimohon;
if ($amaunOverride !== null && $amaunOverride !== '') {
$amaun = round((float) $amaunOverride, 2);
if ($amaun <= 0) {
return [
'ok' => false,
'status' => 422,
'payload' => ['message' => 'Amaun diluluskan tidak sah'],
];
}
}
$tarikh = $this->todayDate();
try {
$applied = DB::connection($mysql)->transaction(function () use ($mysql, $kodcaw, $tarikh, $amaun) {
$modal = ModalOnline::on($mysql)
->where('kodcaw', $kodcaw)
->where('tarikh', $tarikh)
->lockForUpdate()
->first();
$jenis = 'TOPUP';
if (!$modal) {
$modal = ModalOnline::on($mysql)->create([
'tarikh' => $tarikh,
'kodcaw' => $kodcaw,
'had' => $amaun,
'digunakan' => 0.00,
'baki' => $amaun,
'tambah' => 0.00,
'kurang' => 0.00,
'ditutup' => 0,
]);
$modal = ModalOnline::on($mysql)
->where('id', $modal->id)
->lockForUpdate()
->first();
$jenis = 'HAD';
} else {
if ((int) ($modal->ditutup ?? 0) === 1) {
throw new \RuntimeException('MODAL_ONLINE_CLOSED');
}
$modal->tambah = round((float) $modal->tambah + $amaun, 2);
$this->recalcBaki($modal);
$modal->save();
}
return ['modal' => $modal, 'jenis' => $jenis];
});
$modal = $applied['modal'];
$jenis = $applied['jenis'];
$req->status = 'APPROVED';
$req->diluluskan_oleh = $diluluskanOleh;
$req->amaun = $amaun;
$notes = [];
if (abs($amaun - $amaunDimohon) >= 0.01) {
$notes[] = 'Amaun dimohon RM ' . number_format($amaunDimohon, 2)
. ', diluluskan RM ' . number_format($amaun, 2);
}
if ($nota !== null && trim((string) $nota) !== '') {
$notes[] = trim((string) $nota);
}
if ($notes) {
$existing = trim((string) $req->nota);
$req->nota = $existing === ''
? implode(' | ', $notes)
: $existing . ' | ' . implode(' | ', $notes);
}
$req->save();
return [
'ok' => true,
'status' => 200,
'payload' => [
'request' => $req->fresh(),
'jenis' => $jenis,
'modal_online' => $modal,
],
];
} catch (\Throwable $e) {
if ($e->getMessage() === 'MODAL_ONLINE_CLOSED') {
return [
'ok' => false,
'status' => 422,
'payload' => ['message' => 'Modal online hari ini sudah ditutup (EOD). Tidak boleh lulus permohonan.'],
];
}
Log::error('approveTopUp failed: ' . $e->getMessage());
return [
'ok' => false,
'status' => 500,
'payload' => ['message' => 'Gagal lulus permohonan modal online'],
];
}
}
/**
* Operasi reject top-up request.
*
* @return array{ok:bool,status:int,payload:mixed}
*/
public function rejectTopUp($requestId, $diluluskanOleh, $nota = null, $expectedKodcaw = null)
{
$diluluskanOleh = trim((string) $diluluskanOleh);
if ($diluluskanOleh === '') {
return [
'ok' => false,
'status' => 422,
'payload' => ['message' => 'diluluskan_oleh diperlukan'],
];
}
$req = RequestModalOnline::on('mysql7')->where('id', $requestId)->first();
if (!$req) {
return [
'ok' => false,
'status' => 404,
'payload' => ['message' => 'Permohonan tidak dijumpai'],
];
}
if ($expectedKodcaw && $req->kodcaw !== $expectedKodcaw) {
return [
'ok' => false,
'status' => 404,
'payload' => ['message' => 'Permohonan tidak dijumpai'],
];
}
if ($req->status !== 'PENDING') {
return [
'ok' => false,
'status' => 422,
'payload' => [
'message' => 'Hanya permohonan PENDING boleh ditolak',
'status' => $req->status,
],
];
}
$req->status = 'REJECTED';
$req->diluluskan_oleh = $diluluskanOleh;
if ($nota !== null && trim((string) $nota) !== '') {
$req->nota = trim(
trim((string) $req->nota) === ''
? (string) $nota
: $req->nota . ' | ' . $nota
);
}
$req->save();
return [
'ok' => true,
'status' => 200,
'payload' => ['request' => $req],
];
}
/**
* EOD close for one branch: return unused baki via kurang, mark ditutup.
* Also auto-rejects PENDING top-up requests for the branch.
*
* @return array{ok:bool,status:int,payload:mixed}
*/
public function close($kodcaw, $ditutupOleh)
{
$resolved = $this->resolveMysql($kodcaw);
if (!$resolved['ok']) {
return $resolved;
}
$mysql = $resolved['mysql'];
$ditutupOleh = trim((string) $ditutupOleh);
if ($ditutupOleh === '') {
return [
'ok' => false,
'status' => 422,
'payload' => ['message' => 'ditutup_oleh diperlukan'],
];
}
$tarikh = Carbon::now()->toDateString();
$now = Carbon::now();
try {
$result = DB::connection($mysql)->transaction(function () use ($mysql, $kodcaw, $tarikh, $ditutupOleh, $now) {
$modal = ModalOnline::on($mysql)
->where('kodcaw', $kodcaw)
->where('tarikh', $tarikh)
->lockForUpdate()
->first();
if (!$modal) {
return [
'ok' => false,
'status' => 404,
'payload' => [
'message' => 'Tiada modal online hari ini untuk ditutup. Teller belum mohon / PC belum lulus had.',
'missing' => true,
],
];
}
if ((int) ($modal->ditutup ?? 0) === 1) {
return [
'ok' => false,
'status' => 409,
'payload' => [
'message' => 'Modal online sudah ditutup untuk hari ini',
'modal_online' => $modal,
],
];
}
$unused = round((float) $modal->baki, 2);
$modal->kurang = round((float) $modal->kurang + $unused, 2);
$modal->baki = round(
(float) $modal->had + (float) $modal->tambah - (float) $modal->kurang - (float) $modal->digunakan,
2
);
$modal->ditutup = 1;
$modal->ditutup_oleh = $ditutupOleh;
$modal->ditutup_at = $now;
$modal->save();
return [
'ok' => true,
'status' => 200,
'payload' => [
'modal_online' => $modal,
'dikembalikan' => $unused,
],
];
});
if (!$result['ok']) {
return $result;
}
$pendingRejected = RequestModalOnline::on('mysql7')
->where('kodcaw', $kodcaw)
->where('status', 'PENDING')
->get();
foreach ($pendingRejected as $req) {
$req->status = 'REJECTED';
$req->diluluskan_oleh = $ditutupOleh;
$tag = 'Auto reject: EOD close';
$req->nota = trim((string) $req->nota) === ''
? $tag
: trim($req->nota) . ' | ' . $tag;
$req->save();
}
$result['payload']['pending_topup_ditolak'] = $pendingRejected->count();
return $result;
} catch (\Throwable $e) {
Log::error('modal online close failed: ' . $e->getMessage());
return [
'ok' => false,
'status' => 500,
'payload' => ['message' => 'Gagal tutup modal online'],
];
}
}
/**
* Operasi: list today's modal_online across branches.
*
* @return array{ok:bool,status:int,payload:mixed}
*/
public function listToday($zone = 'all', $tarikh = null)
{
$tarikh = $tarikh ?: Carbon::now()->toDateString();
if ($zone == 'all') {
$cawanganAll = Cawangan::on('mysql7')->get();
} else {
$cawanganAll = Cawangan::on('mysql7')->where('zone', $zone)->get();
}
$rows = [];
foreach ($cawanganAll as $cawangan) {
try {
$modal = ModalOnline::on($cawangan['mysql'])
->where('kodcaw', $cawangan['kodcaw'])
->where('tarikh', $tarikh)
->first();
$row = $modal ? $modal->toArray() : [
'tarikh' => $tarikh,
'kodcaw' => $cawangan['kodcaw'],
'had' => 0,
'digunakan' => 0,
'baki' => 0,
'tambah' => 0,
'kurang' => 0,
'ditutup' => 0,
'missing' => true,
];
$row['cawangan_nama'] = $cawangan->nama_cawangan;
$row['missing'] = empty($modal);
$rows[] = $row;
} catch (\Throwable $e) {
Log::warning('listToday modal_online skip ' . $cawangan['kodcaw'] . ': ' . $e->getMessage());
}
}
usort($rows, function ($a, $b) {
return strcmp((string) ($a['kodcaw'] ?? ''), (string) ($b['kodcaw'] ?? ''));
});
$open = 0;
$closed = 0;
$missing = 0;
foreach ($rows as $row) {
if (!empty($row['missing'])) {
$missing++;
} elseif ((int) ($row['ditutup'] ?? 0) === 1) {
$closed++;
} else {
$open++;
}
}
return [
'ok' => true,
'status' => 200,
'payload' => [
'tarikh' => $tarikh,
'bilangan' => count($rows),
'open' => $open,
'closed' => $closed,
'missing' => $missing,
'data' => $rows,
],
];
}
/**
* Operasi bulk EOD close for open branches today.
*
* @return array{ok:bool,status:int,payload:mixed}
*/
public function closeAll($ditutupOleh, $zone = 'all')
{
$ditutupOleh = trim((string) $ditutupOleh);
if ($ditutupOleh === '') {
return [
'ok' => false,
'status' => 422,
'payload' => ['message' => 'ditutup_oleh diperlukan'],
];
}
$list = $this->listToday($zone);
$closed = 0;
$skipped = 0;
$failed = [];
foreach ($list['payload']['data'] as $row) {
if (!empty($row['missing']) || (int) ($row['ditutup'] ?? 0) === 1) {
$skipped++;
continue;
}
$res = $this->close($row['kodcaw'], $ditutupOleh);
if ($res['ok']) {
$closed++;
} else {
$failed[] = [
'kodcaw' => $row['kodcaw'],
'message' => $res['payload']['message'] ?? 'gagal',
];
}
}
return [
'ok' => true,
'status' => 200,
'payload' => [
'closed' => $closed,
'skipped' => $skipped,
'failed' => $failed,
],
];
}
}
File diff suppressed because it is too large Load Diff
+2 -1
View File
@@ -377,7 +377,8 @@ class ImbangDugaService
return $transaction->trans_type !== 'A'; return $transaction->trans_type !== 'A';
})->sum('keuntungan_rebet'); })->sum('keuntungan_rebet');
$total = $total_ansuran + $total_tebus + $get_imbangduga['keun_sebenar']; $backdate_keun_sebenar = isset($get_imbangduga['keun_sebenar']) ? $get_imbangduga['keun_sebenar'] : 0;
$total = $total_ansuran + $total_tebus + $backdate_keun_sebenar;
return $total; return $total;
} }
+60 -28
View File
@@ -58,7 +58,7 @@ class LelonganService
$marhun_lelongan = $this->getMarhunLelongan($total_lelongan, $cawangan_connection); $marhun_lelongan = $this->getMarhunLelongan($total_lelongan, $cawangan_connection);
$cawangan_detail = $this->getCawanganDetail($cawangan_connection); $cawangan_detail = $this->getCawanganDetail($cawangan_connection);
$total_lelongan = $total_lelongan->zip($customer_info, $marhun_lelongan)->map(function ($data) { $total_lelongan = $total_lelongan->zip($customer_info, $marhun_lelongan)->map(function ($data) use ($total_lelongan) {
[$lelong, $customer_info, $marhun_lelongan] = $data; [$lelong, $customer_info, $marhun_lelongan] = $data;
@@ -76,31 +76,38 @@ class LelonganService
'bakipjm' => $lelong['bakipjm'], 'bakipjm' => $lelong['bakipjm'],
'keuntungan' => $lelong['bakiupah'], 'keuntungan' => $lelong['bakiupah'],
'cajlelong' => $lelong['cajlelong'], 'cajlelong' => $lelong['cajlelong'],
'hargaasas' => $lelong['hargaasas'],
'hargajual' => $lelong['hargajual'], 'hargajual' => $lelong['hargajual'],
'baki' => $lelong['baki'], 'baki' => $lelong['baki'],
'teller' => $lelong['teller'], 'teller' => $lelong['teller'],
]; ];
dd($data);
}); });
$total_lelongan = $total_lelongan->groupBy('teller'); $total_lelongan = $total_lelongan->groupBy('teller');
$lelongan_tellers = $total_lelongan->keys(); $result = [];
$total_lelongan = $total_lelongan foreach ($total_lelongan as $teller => $lelongan) {
->zip($total_summary_lelongan_teller) $result[$teller] = [
->map(function ($data) { 'lelongan' => $lelongan->values(),
'summary_lelongan_teller' => $total_summary_lelongan_teller[$teller] ?? [
'total_lelongan' => 0,
'total_berat' => 0,
'total_nilai_marhun' => 0,
'total_pembiayaan' => 0,
'total_bakipjm' => 0,
'total_keuntungan' => 0,
'total_cajlelong' => 0,
'total_hargaasas' => 0,
'total_hargajual' => 0,
'total_baki' => 0,
],
];
}
[$lelongan, $summary] = $data; $total_lelongan = collect($result);
return [
'lelongan' => $lelongan,
'summary_lelongan_teller' => $summary,
];
});
$total_lelongan = $lelongan_tellers->combine($total_lelongan);
$data = [ $data = [
'query' => [ 'query' => [
@@ -143,6 +150,7 @@ class LelonganService
sum(gadai.bakipjm) as total_bakipjm, sum(gadai.bakipjm) as total_bakipjm,
sum(lelong.bakiupah) as total_keuntungan, sum(lelong.bakiupah) as total_keuntungan,
sum(lelong.cajlelong) as total_cajlelong, sum(lelong.cajlelong) as total_cajlelong,
sum(lelong.hargaasas) as total_hargaasas,
sum(lelong.hargajual) as total_hargajual, sum(lelong.hargajual) as total_hargajual,
sum(lelong.baki) as total_baki') sum(lelong.baki) as total_baki')
->get() ->get()
@@ -155,32 +163,54 @@ class LelonganService
'total_bakipjm' => $x['total_bakipjm'], 'total_bakipjm' => $x['total_bakipjm'],
'total_keuntungan' => $x['total_keuntungan'], 'total_keuntungan' => $x['total_keuntungan'],
'total_cajlelong' => $x['total_cajlelong'], 'total_cajlelong' => $x['total_cajlelong'],
'total_hargaasas' => $x['total_hargaasas'],
'total_hargajual' => $x['total_hargajual'], 'total_hargajual' => $x['total_hargajual'],
'total_baki' => $x['total_baki'] 'total_baki' => $x['total_baki']
]; ];
}); });
// dd($total_summary_lelongan);
return $total_summary_lelongan[0]; return $total_summary_lelongan[0];
} }
// private function getTotalSummaryLelonganGroupByTeller(Builder $query_total_lelongan)
// {
// $total_summary_lelongan_groupByTeller = (clone $query_total_lelongan)
// ->selectRaw('count(lelong.norujukan) as total_lelongan,
// sum(lelong.berat) as total_berat,
// sum(lelong.nilaimarhun) as total_nilai_marhun,
// sum(lelong.pinjaman) as total_pembiayaan,
// sum(gadai.bakipjm) as total_bakipjm,
// sum(lelong.bakiupah) as total_keuntungan,
// sum(lelong.cajlelong) as total_cajlelong,
// sum(lelong.hargaasas) as total_hargaasas,
// sum(lelong.hargajual) as total_hargajual,
// sum(lelong.baki) as total_baki')
// ->groupBy('lelong.teller')
// ->get();
// return $total_summary_lelongan_groupByTeller;
// }
private function getTotalSummaryLelonganGroupByTeller(Builder $query_total_lelongan) private function getTotalSummaryLelonganGroupByTeller(Builder $query_total_lelongan)
{ {
return (clone $query_total_lelongan)
$total_summary_lelongan_groupByTeller = (clone $query_total_lelongan) ->selectRaw('
->selectRaw('count(lelong.norujukan) as total_lelongan, lelong.teller,
sum(lelong.berat) as total_berat, count(lelong.norujukan) as total_lelongan,
sum(lelong.nilaimarhun) as total_nilai_marhun, sum(lelong.berat) as total_berat,
sum(lelong.pinjaman) as total_pembiayaan, sum(lelong.nilaimarhun) as total_nilai_marhun,
sum(gadai.bakipjm) as total_bakipjm, sum(lelong.pinjaman) as total_pembiayaan,
sum(lelong.bakiupah) as total_keuntungan, sum(gadai.bakipjm) as total_bakipjm,
sum(lelong.cajlelong) as total_cajlelong, sum(lelong.bakiupah) as total_keuntungan,
sum(lelong.hargajual) as total_hargajual, sum(lelong.cajlelong) as total_cajlelong,
sum(lelong.baki) as total_baki') sum(lelong.hargaasas) as total_hargaasas,
sum(lelong.hargajual) as total_hargajual,
sum(lelong.baki) as total_baki
')
->groupBy('lelong.teller') ->groupBy('lelong.teller')
->get(); ->get()
return $total_summary_lelongan_groupByTeller; ->keyBy('teller'); // ⭐ PENTING
} }
private function getTotalLelongan(Builder $query_total_lelongan) private function getTotalLelongan(Builder $query_total_lelongan)
{ {
$total_lelongan = (clone $query_total_lelongan) $total_lelongan = (clone $query_total_lelongan)
@@ -199,6 +229,7 @@ class LelonganService
'gadai.bakipjm', 'gadai.bakipjm',
'lelong.bakiupah', 'lelong.bakiupah',
'lelong.cajlelong', 'lelong.cajlelong',
'lelong.hargaasas',
'lelong.hargajual', 'lelong.hargajual',
'lelong.baki') 'lelong.baki')
->orderBy('lelong.teller') ->orderBy('lelong.teller')
@@ -311,6 +342,7 @@ class LelonganService
'bakipjm' => $lelong['bakipjm'], 'bakipjm' => $lelong['bakipjm'],
'keuntungan' => $lelong['bakiupah'], 'keuntungan' => $lelong['bakiupah'],
'cajlelong' => $lelong['cajlelong'], 'cajlelong' => $lelong['cajlelong'],
'hargaasas' => $lelong['hargaasas'],
'hargajual' => $lelong['hargajual'], 'hargajual' => $lelong['hargajual'],
'baki' => $lelong['baki'], 'baki' => $lelong['baki'],
'teller' => $lelong['teller'], 'teller' => $lelong['teller'],
+1 -1
View File
@@ -398,7 +398,7 @@ class OnePercentService
$t_gadai = Carbon::parse($gadai->t_gadai); $t_gadai = Carbon::parse($gadai->t_gadai);
$t_bayaran = Carbon::parse($trans->tarikh_bayaran); $t_bayaran = Carbon::parse($trans->tarikh_bayaran);
if ($t_gadai->month === $t_bayaran->month && $t_gadai->year === $t_bayaran->year) { if (($t_gadai->month == $t_bayaran->month) && ($t_gadai->year == $t_bayaran->year)) {
return false; return false;
}else{ }else{
return true; return true;
@@ -1322,7 +1322,7 @@ class RingkasanHarianService
return floatval($totalSerahan); return floatval($totalSerahan);
} }
return floatval(0); return floatval($serahanpkbTawarruq);
} }
+53
View File
@@ -0,0 +1,53 @@
<?php
namespace App\Services;
use Illuminate\Support\Facades\Http;
use Illuminate\Support\Facades\Log;
class StaffNotificationClient
{
/**
* Ask kaunter to persist a staff inbox row. Never throws.
*
* @param array $payload
* @return void
*/
public function notify(array $payload)
{
$base = rtrim((string) config('kaunter.url'), '/');
$secret = (string) config('kaunter.notification_secret');
if ($base === '' || $secret === '') {
Log::info('Staff notification skipped: KAUNTER_URL or INTERNAL_NOTIFICATION_SECRET is empty');
return;
}
$timeout = (int) config('kaunter.notification_timeout', 3);
if ($timeout < 1) {
$timeout = 3;
}
try {
$response = Http::timeout($timeout)
->withHeaders([
'X-Internal-Token' => $secret,
'Accept' => 'application/json',
])
->asJson()
->post($base . '/internal/notifications', $payload);
if (!$response->successful()) {
Log::warning('Staff notification to kaunter failed', [
'status' => $response->status(),
'body' => $response->body(),
'type' => isset($payload['type']) ? $payload['type'] : null,
]);
}
} catch (\Throwable $e) {
Log::warning('Staff notification to kaunter errored: '.$e->getMessage(), [
'type' => isset($payload['type']) ? $payload['type'] : null,
]);
}
}
}
@@ -0,0 +1,100 @@
<?php
namespace App\Services\Whatsapp;
use Illuminate\Support\Facades\Http;
use Illuminate\Support\Facades\Log;
class WhatsappCloudClient
{
public function isConfigured()
{
return trim((string) config('whatsapp.token')) !== ''
&& trim((string) config('whatsapp.phone_number_id')) !== '';
}
/**
* Malaysia MSISDN for Graph API, e.g. 60193450165.
*
* @return string|null
*/
public function normalizeMsisdn($raw)
{
$digits = preg_replace('/\D+/', '', (string) $raw);
if ($digits === '') {
return null;
}
if (strpos($digits, '60') === 0) {
return $digits;
}
if (strpos($digits, '0') === 0) {
return '60' . substr($digits, 1);
}
return '60' . $digits;
}
/**
* @param string $to
* @param string $templateName
* @param string $lang
* @param array<int,string> $bodyParams
* @return \Illuminate\Http\Client\Response
*/
public function sendTemplate($to, $templateName, $lang, array $bodyParams = [])
{
$payload = [
'messaging_product' => 'whatsapp',
'to' => $to,
'type' => 'template',
'template' => [
'name' => $templateName,
'language' => ['code' => $lang],
],
];
if (count($bodyParams) > 0) {
$payload['template']['components'] = [[
'type' => 'body',
'parameters' => array_map(function ($text) {
return [
'type' => 'text',
'text' => $this->sanitizeParam($text),
];
}, array_values($bodyParams)),
]];
}
$version = config('whatsapp.api_version', 'v25.0');
$phoneId = config('whatsapp.phone_number_id');
$url = 'https://graph.facebook.com/' . $version . '/' . $phoneId . '/messages';
$response = Http::withToken(config('whatsapp.token'))
->acceptJson()
->asJson()
->post($url, $payload);
if (!$response->successful()) {
Log::error('WhatsApp Cloud send failed', [
'to' => $to,
'template' => $templateName,
'status' => $response->status(),
'body' => $response->json() ?: $response->body(),
]);
}
return $response;
}
protected function sanitizeParam($text)
{
$text = trim(preg_replace('/\s+/', ' ', (string) $text));
if ($text === '') {
return '-';
}
return mb_substr($text, 0, 200);
}
}
+3
View File
@@ -2,11 +2,14 @@
namespace App\Support; namespace App\Support;
use App\Cawangan;
use App\KadarUpah; use App\KadarUpah;
use App\Pampasan;
use App\Support\v1\GadaiV1 as Version1Gadai; use App\Support\v1\GadaiV1 as Version1Gadai;
use App\Services\MasterServices; use App\Services\MasterServices;
use App\Support\v1\Penebusan; use App\Support\v1\Penebusan;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request as HttpRequest; use Illuminate\Http\Request as HttpRequest;
use Illuminate\Support\Facades\Log; use Illuminate\Support\Facades\Log;
+13
View File
@@ -15,6 +15,8 @@ use App\KomuditiPurchase;
use App\KomuditiTransaksi; use App\KomuditiTransaksi;
use App\Marhun; use App\Marhun;
use App\Moratorium; use App\Moratorium;
use App\Palsu;
use App\Pampasan;
use App\Support\OnePercent; use App\Support\OnePercent;
use App\Support\Tawarruq; use App\Support\Tawarruq;
use App\Support\v1\Calculation as V1Calculation; use App\Support\v1\Calculation as V1Calculation;
@@ -479,6 +481,17 @@ class Penebusan
$upah_rebet_sebenar = $harga_tebus - $gadai['bakipjm']; $upah_rebet_sebenar = $harga_tebus - $gadai['bakipjm'];
} }
$isPampasan = Pampasan::on($cawangan['mysql'])->where('norujukan', $request->norujukan)->exists();
if($isPampasan){
$barang_kes = Palsu::on($cawangan['mysql'])->where('norujukan', $norujukan)->first();
$harga_tebus = $barang_kes->untung + $barang_kes->pembiayaan;
$upah_tebus = $barang_kes->untung;
$upah_rebet = $this->kiraUpahRebetSebenar($kodcaw,$norujukan);
$upah_rebet_sebenar = $barang_kes->untung;
$rebet = $gadai['hargajualan'] - $harga_tebus;
}
$create_tebus = Tebus::on($cawangan['mysql'])->create([ $create_tebus = Tebus::on($cawangan['mysql'])->create([
'kodcaw'=> $kodcaw, 'kodcaw'=> $kodcaw,
+56 -2
View File
@@ -2,8 +2,11 @@
namespace App\Support\v2; namespace App\Support\v2;
use App\Feature;
use App\KadarRebet;
use App\KadarUpah; use App\KadarUpah;
use Illuminate\Http\Request; use Illuminate\Http\Request;
use Illuminate\Support\Facades\Schema;
class Calculation class Calculation
{ {
@@ -55,7 +58,7 @@ class Calculation
return $ujrah_sebenar; return $ujrah_sebenar;
} }
public function kiraanKeuntunganRebet(float $pembiayaan = 0.0,float $nilaimarhun = 0.0,float $kadarujrah = 0.0,float $margin = 0.0){ public function kiraanKeuntunganRebet(float $pembiayaan = 0.0,float $nilaimarhun = 0.0,float $kadarujrah = 0.0,float $margin = 0.0, $kodcaw = null){
$this->one_percent = $this->getKadarUpah($nilaimarhun); $this->one_percent = $this->getKadarUpah($nilaimarhun);
@@ -66,8 +69,59 @@ class Calculation
$ujrah_sebenar = (!empty($ujrah_sebenar)) ? $this->getRoundedMethod($ujrah_sebenar) : 0; $ujrah_sebenar = (!empty($ujrah_sebenar)) ? $this->getRoundedMethod($ujrah_sebenar) : 0;
$keuntungan = $onepercent + $ujrah_sebenar; $keuntungan = $onepercent + $ujrah_sebenar;
$annur = $this->kiraanDiskaunAnnur($kodcaw, $pembiayaan, $keuntungan);
return ['keuntungan' => $keuntungan,'onepercent' => $onepercent, 'ujrah' => $ujrah_sebenar]; return [
'keuntungan' => $keuntungan,
'onepercent' => $onepercent,
'ujrah' => $ujrah_sebenar,
'diskaun' => $annur['diskaun'],
'kadarrebet' => $annur['kadarrebet'],
];
}
/**
* Annur promotional discount. Other cawangan get 0 unless rebet_annur is enabled.
*/
public function kiraanDiskaunAnnur($kodcaw, float $pembiayaan = 0.0, float $keuntungan = 0.0)
{
$empty = ['kadarrebet' => 0, 'diskaun' => 0];
try {
if (!$kodcaw || !Feature::enabled($kodcaw, Feature::REBET_ANNUR)) {
return $empty;
}
} catch (\Exception $e) {
return $empty;
}
$percent = $this->kiraanRebetAnnur($pembiayaan);
if ($percent <= 0 || $keuntungan <= 0) {
return ['kadarrebet' => $percent, 'diskaun' => 0];
}
return [
'kadarrebet' => $percent,
'diskaun' => $this->getRoundedMethod($keuntungan * ($percent / 100)),
];
}
private function kiraanRebetAnnur(float $pembiayaan = 0.0)
{
try {
if (!Schema::connection('mysql7')->hasTable('kadar_rebet')) {
return 0;
}
$kadarrebet = KadarRebet::on('mysql7')
->where('pembiayaan_min', '<=', $pembiayaan)
->where('pembiayaan_max', '>=', $pembiayaan)
->sum('kadarrebet');
return (float) $kadarrebet;
} catch (\Exception $e) {
return 0;
}
} }
public function kiraanKeuntunganSebenar(float $pembiayaan = 0.0,float $nilaimarhun = 0.0,float $kadarujrah = 0.0,float $margin = 0.0){ public function kiraanKeuntunganSebenar(float $pembiayaan = 0.0,float $nilaimarhun = 0.0,float $kadarujrah = 0.0,float $margin = 0.0){
+67 -43
View File
@@ -5,6 +5,7 @@ namespace App\Support\v2;
use App\Audit; use App\Audit;
use App\Cawangan; use App\Cawangan;
use App\Customer; use App\Customer;
use App\Feature;
use App\KadarUpah; use App\KadarUpah;
use App\Support\v2\Calculation; use App\Support\v2\Calculation;
use Carbon\Carbon; use Carbon\Carbon;
@@ -58,31 +59,34 @@ class GadaiV2
} }
} }
private function getKadarUpahAnggota($nokp,$total_nilai_marhun = 0,$groupid = 2) : Float{ private function getKadarUpahAnggota($nokp, $total_nilai_marhun = 0, $groupid = 2): ?float
//Log::info('DEBUG NOKP:' . $nokp); {
if($nokp){ if (!$nokp) {
$customer = Customer::on('mysql7') return null; // tiada nokp = tak boleh tentukan kadar
->select('tag_anggota')
->where(function($q) use ($nokp) {
$q->where('kpbaru', $nokp)
->orWhere('kplama', $nokp);
})
->first();
$customer = $customer ? $customer->toArray() : [];
if(isset($customer) && $customer['tag_anggota'] == 1){
return 0.16;
}else{
return KadarUpah::where('min', '<=', $total_nilai_marhun)
->where('max', '>=', $total_nilai_marhun)
->where('group_id', $groupid)
->value('kadarujrah');
}
}
return 0.0;
} }
$customer = Customer::on('mysql7')
->select('tag_anggota')
->where(function ($q) use ($nokp) {
$q->where('kpbaru', $nokp)
->orWhere('kplama', $nokp);
})
->first();
$customer = $customer ? $customer->toArray() : [];
if (isset($customer['tag_anggota']) && $customer['tag_anggota'] == 1) {
return 0.00; // ahli — kadar 0.00 memang sah
}
$kadar = KadarUpah::where('min', '<=', $total_nilai_marhun)
->where('max', '>=', $total_nilai_marhun)
->where('group_id', $groupid)
->value('kadarujrah');
return is_null($kadar) ? null : (float) $kadar; // tak jumpa row = null (block)
}
public function createMarhun($norujukan,HttpRequest $request){ public function createMarhun($norujukan,HttpRequest $request){
$current = Carbon::now(); $current = Carbon::now();
$current = new Carbon(); $current = new Carbon();
@@ -108,19 +112,18 @@ class GadaiV2
$total_nilai_marhun = Marhun::on($cawangan['mysql'])->where('norujukan','=',$norujukan)->sum('n_marhun'); $total_nilai_marhun = Marhun::on($cawangan['mysql'])->where('norujukan','=',$norujukan)->sum('n_marhun');
$total_berat = Marhun::on($cawangan['mysql'])->where('norujukan','=',$norujukan)->sum('berat'); $total_berat = Marhun::on($cawangan['mysql'])->where('norujukan','=',$norujukan)->sum('berat');
$kadar_raw = $this->getKadarUpahAnggota($request->nokp, $total_nilai_marhun, $cawangan['group_id']); $kadar_raw = $this->getKadarUpahAnggota($request->nokp, $total_nilai_marhun, $cawangan['group_id']);
if (empty($kadar_raw) || $kadar_raw == 0) { if (is_null($kadar_raw)) {
Log::error('[BLOCKED] Kadar upah tidak dijumpai', [
Log::error('[BLOCKED] Kadar upah kosong / 0', [ 'nokp' => $request->nokp,
'nokp' => $request->nokp, 'total_nilai_marhun' => $total_nilai_marhun,
'total_nilai_marhun' => $total_nilai_marhun, 'group_id' => $cawangan['group_id'],
'group_id' => $cawangan['group_id'], ]);
]); throw new \Exception("Kadar upah tidak dijumpai, transaksi dibatalkan!");
}
throw new \Exception("Kadar upah kosong / 0, transaksi dibatalkan!");
}
// $kadar_raw = 0.00 (ahli) akan lepas ke sini dan diteruskan
// query kadar upah lama // query kadar upah lama
// $kadar_raw = KadarUpah::where('min','<=',$total_nilai_marhun)->where('max','>=',$total_nilai_marhun)->first(); // $kadar_raw = KadarUpah::where('min','<=',$total_nilai_marhun)->where('max','>=',$total_nilai_marhun)->first();
@@ -135,14 +138,13 @@ class GadaiV2
$upah12 = $onepercentservices->getRoundedMethod($upah1 * 12); $upah12 = $onepercentservices->getRoundedMethod($upah1 * 12);
$ujrah = $onepercentservices->getRoundedMethod($keuntungan['ujrah']); $ujrah = $onepercentservices->getRoundedMethod($keuntungan['ujrah']);
$onepercent = $onepercentservices->getRoundedMethod($keuntungan['onepercent']); $onepercent = $onepercentservices->getRoundedMethod($keuntungan['onepercent']);
$annur = $onepercentservices->kiraanDiskaunAnnur($request->kodcaw, $request->pinjaman, $keuntungan['keuntungan']);
$hargajualan = $request->pinjaman + $upah12; $hargajualan = $request->pinjaman + $upah12;
$akrual = $this->kiraupahTawarruqStokAuditUjrahOnePercent(0.5,0,$kadar_raw,$request->pinjaman,$total_nilai_marhun,$margin_pinjam); $akrual = $this->kiraupahTawarruqStokAuditUjrahOnePercent(0.5,0,$kadar_raw,$request->pinjaman,$total_nilai_marhun,$margin_pinjam);
$gadai = Gadai::on($cawangan['mysql']) $gadaiFields = [
->where('norujukan','=',$norujukan)
->update(array(
'nilaimarhun' => $total_nilai_marhun, 'nilaimarhun' => $total_nilai_marhun,
'berat'=> $total_berat, 'berat'=> $total_berat,
'pinjaman' => $request->pinjaman, 'pinjaman' => $request->pinjaman,
@@ -174,7 +176,23 @@ class GadaiV2
'tagbaru' => 1, 'tagbaru' => 1,
'tunggakanujrah' => $akrual['ujrah'], 'tunggakanujrah' => $akrual['ujrah'],
'tunggakanonepercent' => $akrual['keuntungan'], 'tunggakanonepercent' => $akrual['keuntungan'],
)); ];
if (Feature::enabled($request->kodcaw, Feature::REBET_ANNUR)) {
$requestedKadar = (float) $request->input('kadar_rebate', 0);
$requestedDiskaun = (float) $request->input('rebate', 0);
if ($requestedKadar > 0 || $requestedDiskaun > 0) {
$gadaiFields['kadarrebet'] = $requestedKadar;
$gadaiFields['diskaun'] = $requestedDiskaun;
} elseif (($request->transaction ?? '') === 'Daftar Gadai') {
$gadaiFields['kadarrebet'] = $annur['kadarrebet'];
$gadaiFields['diskaun'] = $annur['diskaun'];
}
}
$gadai = Gadai::on($cawangan['mysql'])
->where('norujukan','=',$norujukan)
->update($gadaiFields);
$new_data = Gadai::on($cawangan['mysql'])->where('norujukan','=',$norujukan)->first(); $new_data = Gadai::on($cawangan['mysql'])->where('norujukan','=',$norujukan)->first();
@@ -238,14 +256,15 @@ class GadaiV2
} }
$bilang_bln = $tempoh - $gadai_data['tempohbayar']; $bilang_bln = $tempoh - $gadai_data['tempohbayar'];
$upah = $onepercentservices->kiraanKeuntunganRebet($gadai_data['bakipjm'],$gadai_data['nilaimarhun'],$gadai_data['kadarupah'],$gadai_data['margin_semasa']); $upah = $onepercentservices->kiraanKeuntunganRebet($gadai_data['bakipjm'],$gadai_data['nilaimarhun'],$gadai_data['kadarupah'],$gadai_data['margin_semasa'], $this->kodcaw);
//$upahrebet_raw = $bilang_bln * $upah['keuntungan']; //$upahrebet_raw = $bilang_bln * $upah['keuntungan'];
$onepercent = $onepercentservices->getRoundedMethod($bilang_bln * $upah['onepercent']); $onepercent = $onepercentservices->getRoundedMethod($bilang_bln * $upah['onepercent']);
$ujrah = $onepercentservices->getRoundedMethod($bilang_bln * $upah['ujrah']); $ujrah = $onepercentservices->getRoundedMethod($bilang_bln * $upah['ujrah']);
$upahrebet_raw = $onepercent + $ujrah; $upahrebet_raw = $onepercent + $ujrah;
$upahrebet_raw = $onepercentservices->getRoundedMethod($upahrebet_raw); $upahrebet_raw = $onepercentservices->getRoundedMethod($upahrebet_raw);
$upahrebet_raw = $upahrebet_raw - ($upah['diskaun'] ?? 0);
return $upahrebet_raw; return $upahrebet_raw;
} }
@@ -280,7 +299,7 @@ class GadaiV2
$margin_semasa = ($gadai['bakipjm'] / $gadai['nilaimarhun']) * 100; $margin_semasa = ($gadai['bakipjm'] / $gadai['nilaimarhun']) * 100;
$keuntungan = $onepercent->kiraanKeuntunganRebet($gadai['bakipjm'],$gadai['nilaimarhun'],$gadai['kadarupah'],$gadai['margin_semasa']); $keuntungan = $onepercent->kiraanKeuntunganRebet($gadai['bakipjm'],$gadai['nilaimarhun'],$gadai['kadarupah'],$gadai['margin_semasa'], $kodcaw);
$ujrahasal = $onepercent->kiraanUjrahSebenar($gadai['nilaimarhun'],$gadai['kadarupah'],$gadai['percentpinj']); $ujrahasal = $onepercent->kiraanUjrahSebenar($gadai['nilaimarhun'],$gadai['kadarupah'],$gadai['percentpinj']);
$onepercentasal = $gadai['pinjaman'] * (1/100); $onepercentasal = $gadai['pinjaman'] * (1/100);
@@ -317,7 +336,7 @@ class GadaiV2
$keun = $onepercent->getRoundedMethod($onepercentasal * $bilang_bln); $keun = $onepercent->getRoundedMethod($onepercentasal * $bilang_bln);
$keuntungan_rebate = $onepercent->getRoundedMethod($keuntungan['onepercent'] * $bilang_bln); $keuntungan_rebate = $onepercent->getRoundedMethod($keuntungan['onepercent'] * $bilang_bln);
$transaction_upah = TransaksiKeuntungan::on('mysql7')->create([ $transactionUpahFields = [
'norujukan' => $norujukan, 'norujukan' => $norujukan,
'bayaran_keuntungan' => $upahsemasa, 'bayaran_keuntungan' => $upahsemasa,
'bayaran_pembiayaan' => $baki_bayaran, 'bayaran_pembiayaan' => $baki_bayaran,
@@ -331,7 +350,12 @@ class GadaiV2
'tempoh' => $gadai['tempoh'], 'tempoh' => $gadai['tempoh'],
'beza_tempoh' => $bilang_bln, 'beza_tempoh' => $bilang_bln,
'margin_semasa' => $margin_semasa, 'margin_semasa' => $margin_semasa,
]); ];
if (Feature::enabled($kodcaw, Feature::REBET_ANNUR)) {
$transactionUpahFields['kadardiskaun'] = $keuntungan['diskaun'] ?? 0;
}
$transaction_upah = TransaksiKeuntungan::on('mysql7')->create($transactionUpahFields);
$transaksi_gadai = TransaksiGadai::on('mysql7')->create([ $transaksi_gadai = TransaksiGadai::on('mysql7')->create([
'kodcaw' => $old_data['kodcaw'], 'kodcaw' => $old_data['kodcaw'],
+54 -10
View File
@@ -5,6 +5,7 @@ namespace App\Support\v2;
use App\Advansur; use App\Advansur;
use App\Audit; use App\Audit;
use App\Cawangan; use App\Cawangan;
use App\Feature;
use App\KadarUpah; use App\KadarUpah;
use App\Support\v2\Calculation; use App\Support\v2\Calculation;
use Carbon\Carbon; use Carbon\Carbon;
@@ -39,6 +40,32 @@ class Penebusan
$this->cawangan_info = $cawangan_info; $this->cawangan_info = $cawangan_info;
} }
private function diskaunAnnur($kodcaw, $gadai)
{
try {
if (!Feature::enabled($kodcaw, Feature::REBET_ANNUR)) {
return 0.0;
}
} catch (\Exception $e) {
return 0.0;
}
return (float) ($gadai['diskaun'] ?? 0);
}
private function tebusAnnurFields($kodcaw, $diskaun)
{
try {
if (!Feature::enabled($kodcaw, Feature::REBET_ANNUR)) {
return [];
}
} catch (\Exception $e) {
return [];
}
return ['diskaun_rebate' => $diskaun];
}
public function tebusTawarruq($kodcaw,$norujukan){ public function tebusTawarruq($kodcaw,$norujukan){
$onepercentservices = new Calculation(); $onepercentservices = new Calculation();
@@ -53,7 +80,8 @@ class Penebusan
$jeniskeuntungan = ($gadai_data['tagbaru'] == 1) ? 'onepercent' : 'asal'; $jeniskeuntungan = ($gadai_data['tagbaru'] == 1) ? 'onepercent' : 'asal';
$rebet = $this->rebetselepastawarruq($kodcaw,$norujukan,$jeniskeuntungan); $rebet = $this->rebetselepastawarruq($kodcaw,$norujukan,$jeniskeuntungan);
$harga_tebus = $gadai_data['bakihargajualan'] - $rebet; $diskaun = $this->diskaunAnnur($kodcaw, $gadai_data);
$harga_tebus = $gadai_data['bakihargajualan'] - $rebet - $diskaun;
// $hargatebus = round($harga_tebus,PHP_ROUND_HALF_UP); // $hargatebus = round($harga_tebus,PHP_ROUND_HALF_UP);
// $hargatebus = bcdiv(round($harga_tebus,2),1,1); // $hargatebus = bcdiv(round($harga_tebus,2),1,1);
@@ -485,6 +513,8 @@ class Penebusan
$gadai = Gadai::on($cawangan['mysql'])->where('norujukan','=',$norujukan)->first(); $gadai = Gadai::on($cawangan['mysql'])->where('norujukan','=',$norujukan)->first();
$diskaun = $this->diskaunAnnur($kodcaw, $gadai);
//check duplicate //check duplicate
$data = Transaction::on('mysql7')->where('norujukan','=',$norujukan)->whereIn('trans_type', ['P', 'T', 'S'])->first(); $data = Transaction::on('mysql7')->where('norujukan','=',$norujukan)->whereIn('trans_type', ['P', 'T', 'S'])->first();
@@ -502,7 +532,6 @@ class Penebusan
$harga_tebus = $this->hargaTebusTawarruq($kodcaw,$norujukan,$request->jeniskeuntungan); $harga_tebus = $this->hargaTebusTawarruq($kodcaw,$norujukan,$request->jeniskeuntungan);
$upah_tebus = $this->kiraupahTawarruq($norujukan); $upah_tebus = $this->kiraupahTawarruq($norujukan);
$upah_rebet = $this->kiraUpahRebetSebenar($kodcaw,$norujukan); $upah_rebet = $this->kiraUpahRebetSebenar($kodcaw,$norujukan);
$upah_rebet_sebenar = $harga_tebus['harga'] - $gadai['bakipjm'];
if($request->jeniskeuntungan == 'onepercent'){ if($request->jeniskeuntungan == 'onepercent'){
$array_onepercent = $this->kiraupahUjrahOnePercent($kodcaw,$norujukan); $array_onepercent = $this->kiraupahUjrahOnePercent($kodcaw,$norujukan);
@@ -514,10 +543,15 @@ class Penebusan
$ujrah = $array_onepercent['ujrah']; $ujrah = $array_onepercent['ujrah'];
$onepercent = $array_onepercent['onepercent']; $onepercent = $array_onepercent['onepercent'];
} }
$harga_tebus['harga'] -= $diskaun;
$upah_rebet_sebenar = $harga_tebus['harga'] - $gadai['bakipjm'];
} }
$bayaran_keuntungan_bersih = max(0, $upah_rebet_sebenar);
$create_tebus = Tebus::on($cawangan['mysql'])->create([
$create_tebus = Tebus::on($cawangan['mysql'])->create(array_merge([
'kodcaw'=> $kodcaw, 'kodcaw'=> $kodcaw,
'norujukan'=> $norujukan, 'norujukan'=> $norujukan,
'nopelanggan' => $request->nopelanggan, 'nopelanggan' => $request->nopelanggan,
@@ -543,7 +577,7 @@ class Penebusan
'teller' => $request->teller, 'teller' => $request->teller,
'ujrah' => $ujrah_rebet, 'ujrah' => $ujrah_rebet,
'onepercent' => $onepercent_rebet, 'onepercent' => $onepercent_rebet,
]); ], $this->tebusAnnurFields($kodcaw, $diskaun)));
$create_inoutmar = InOutMar::on($cawangan['mysql'])->create([ $create_inoutmar = InOutMar::on($cawangan['mysql'])->create([
'tarikh' => $current->toDateString(), 'tarikh' => $current->toDateString(),
@@ -561,7 +595,7 @@ class Penebusan
$transaction_upah = TransaksiKeuntungan::on('mysql7')->create([ $transaction_upah = TransaksiKeuntungan::on('mysql7')->create([
'norujukan' => $norujukan, 'norujukan' => $norujukan,
'bayaran_keuntungan' => $upah_tebus, 'bayaran_keuntungan' => $bayaran_keuntungan_bersih,
'bayaran_pembiayaan' => $gadai['bakipjm'], 'bayaran_pembiayaan' => $gadai['bakipjm'],
'keuntungan_rebet' => $upah_rebet_sebenar, 'keuntungan_rebet' => $upah_rebet_sebenar,
'tarikh_bayaran'=> $current, 'tarikh_bayaran'=> $current,
@@ -651,6 +685,8 @@ class Penebusan
$gadai = Gadai::on($cawangan['mysql'])->where('norujukan','=',$norujukan)->first(); $gadai = Gadai::on($cawangan['mysql'])->where('norujukan','=',$norujukan)->first();
$diskaun = $this->diskaunAnnur($kodcaw, $gadai);
//check duplicate //check duplicate
$data = Transaction::on('mysql7')->where('norujukan','=',$norujukan)->where('trans_type','=','AT')->first(); $data = Transaction::on('mysql7')->where('norujukan','=',$norujukan)->where('trans_type','=','AT')->first();
@@ -668,7 +704,6 @@ class Penebusan
$harga_tebus = $this->hargaTebusTawarruq($kodcaw,$norujukan,$request->jeniskeuntungan); $harga_tebus = $this->hargaTebusTawarruq($kodcaw,$norujukan,$request->jeniskeuntungan);
$upah_tebus = $this->kiraupahTawarruq($norujukan); $upah_tebus = $this->kiraupahTawarruq($norujukan);
$upah_rebet = $this->kiraUpahRebetSebenar($kodcaw,$norujukan); $upah_rebet = $this->kiraUpahRebetSebenar($kodcaw,$norujukan);
$upah_rebet_sebenar = $harga_tebus['harga'] - $gadai['bakipjm'];
if($request->jeniskeuntungan == 'onepercent'){ if($request->jeniskeuntungan == 'onepercent'){
$array_onepercent = $this->kiraupahUjrahOnePercent($kodcaw,$norujukan); $array_onepercent = $this->kiraupahUjrahOnePercent($kodcaw,$norujukan);
@@ -681,6 +716,9 @@ class Penebusan
$ujrah = $array_onepercent['ujrah']; $ujrah = $array_onepercent['ujrah'];
$onepercent = $array_onepercent['onepercent']; $onepercent = $array_onepercent['onepercent'];
} }
$harga_tebus['harga'] -= $diskaun;
$upah_rebet_sebenar = $harga_tebus['harga'] - $gadai['bakipjm'];
} }
$update_gadai = Gadai::on($cawangan['mysql'])->where('norujukan','=',$norujukan)->update(array( $update_gadai = Gadai::on($cawangan['mysql'])->where('norujukan','=',$norujukan)->update(array(
@@ -690,7 +728,7 @@ class Penebusan
// $upah_rebet = $this->kiraUpahRebet($kodcaw,$norujukan); // $upah_rebet = $this->kiraUpahRebet($kodcaw,$norujukan);
$create_tebus = Tebus::on($cawangan['mysql'])->create([ $create_tebus = Tebus::on($cawangan['mysql'])->create(array_merge([
'kodcaw'=> $kodcaw, 'kodcaw'=> $kodcaw,
'norujukan'=> $norujukan, 'norujukan'=> $norujukan,
'nopelanggan' => $request->nopelanggan, 'nopelanggan' => $request->nopelanggan,
@@ -716,7 +754,7 @@ class Penebusan
'teller' => $request->teller, 'teller' => $request->teller,
'ujrah' => $ujrah_rebet, 'ujrah' => $ujrah_rebet,
'onepercent' => $onepercent_rebet, 'onepercent' => $onepercent_rebet,
]); ], $this->tebusAnnurFields($kodcaw, $diskaun)));
$create_inoutmar = InOutMar::on($cawangan['mysql'])->create([ $create_inoutmar = InOutMar::on($cawangan['mysql'])->create([
'tarikh' => $current->toDateString(), 'tarikh' => $current->toDateString(),
@@ -734,9 +772,11 @@ class Penebusan
$bayaran_pembiayaan = $request->totalbayaran - $request->bakiupah; $bayaran_pembiayaan = $request->totalbayaran - $request->bakiupah;
$bayaran_keuntungan_bersih = max(0, $upah_rebet_sebenar);
$transaction_upah = TransaksiKeuntungan::on('mysql7')->create([ $transaction_upah = TransaksiKeuntungan::on('mysql7')->create([
'norujukan' => $norujukan, 'norujukan' => $norujukan,
'bayaran_keuntungan' => $upah_tebus, 'bayaran_keuntungan' => $bayaran_keuntungan_bersih,
'bayaran_pembiayaan' => $bayaran_pembiayaan, 'bayaran_pembiayaan' => $bayaran_pembiayaan,
'keuntungan_rebet' => $upah_rebet_sebenar, 'keuntungan_rebet' => $upah_rebet_sebenar,
'tarikh_bayaran'=> $current, 'tarikh_bayaran'=> $current,
@@ -1131,12 +1171,16 @@ class Penebusan
$onepercent_rebet = $array_onepercent_rebet['onepercent'] - $upah_rebet['onepercent']; $onepercent_rebet = $array_onepercent_rebet['onepercent'] - $upah_rebet['onepercent'];
$ujrah_rebet = $array_onepercent_rebet['ujrah'] - $upah_rebet['ujrah']; $ujrah_rebet = $array_onepercent_rebet['ujrah'] - $upah_rebet['ujrah'];
$diskaun = $this->diskaunAnnur($kodcaw, $gadai);
$harga_tebus['harga'] -= $diskaun;
$upah_rebet_sebenar = $harga_tebus['harga'] - $gadai['bakipjm']; $upah_rebet_sebenar = $harga_tebus['harga'] - $gadai['bakipjm'];
$bayaran_keuntungan_bersih = max(0, $upah_rebet_sebenar);
try{ try{
TransaksiKeuntungan::on('mysql7')->create([ TransaksiKeuntungan::on('mysql7')->create([
'norujukan' => $norujukan, 'norujukan' => $norujukan,
'bayaran_keuntungan' => $upah_tebus, 'bayaran_keuntungan' => $bayaran_keuntungan_bersih,
'bayaran_pembiayaan' => $bayaran_pembiayaan, 'bayaran_pembiayaan' => $bayaran_pembiayaan,
'keuntungan_rebet' => $upah_rebet_sebenar, 'keuntungan_rebet' => $upah_rebet_sebenar,
'tarikh_bayaran'=> $current, 'tarikh_bayaran'=> $current,
+2 -1
View File
@@ -52,7 +52,8 @@ class Tebus extends Model
'pinjamanterkini', 'pinjamanterkini',
'tarikhbyrn', 'tarikhbyrn',
'ujrah', 'ujrah',
'onepercent' 'onepercent',
'diskaun_rebate'
]; ];
/** /**
+1 -1
View File
@@ -14,7 +14,7 @@ class TransaksiKeuntungan extends Model
* @var array * @var array
*/ */
protected $fillable = [ protected $fillable = [
'norujukan','bayaran_keuntungan','tarikh_bayaran','kodcaw','bayaran_pembiayaan','keuntungan_rebet','ujrah','ujrah_rebet','onepercent','onepercent_rebet','tempoh','beza_tempoh','margin_semasa','rounded' 'norujukan','bayaran_keuntungan','tarikh_bayaran','kodcaw','bayaran_pembiayaan','keuntungan_rebet','ujrah','ujrah_rebet','onepercent','onepercent_rebet','tempoh','beza_tempoh','margin_semasa','rounded','kadardiskaun'
]; ];
/** /**
+32
View File
@@ -0,0 +1,32 @@
<?php
namespace App;
use Illuminate\Database\Eloquent\Model;
class WTDSimulasi extends Model
{
/**
* The attributes that are mass assignable.
*
* @var array
*/
protected $connection = 'mysql7';
protected $table = 'wtd_simulasi';
protected $fillable = [
'bulan',
'tahun',
'kodcaw',
'jumlah_sag',
'pembiayaan',
'baki',
'simulasi',
];
/**
* The attributes excluded from the model's JSON form.
*
* @var array
*/
protected $hidden = [];
}
+1
View File
@@ -0,0 +1 @@
/cache
+36 -5
View File
@@ -23,6 +23,33 @@ $app = new Laravel\Lumen\Application(
dirname(__DIR__) dirname(__DIR__)
); );
/*
| Laravel's storage_path() helper resolves app('path.storage'). Lumen does not
| register that binding by default; config files that call storage_path() at
| load time (e.g. config/logging.php) would fail without this.
*/
$app->instance('path.storage', $app->storagePath());
/*
| Laravel's Foundation helpers are loaded before Lumen's and win for names like
| response() and url(). Those helpers resolve Illuminate\Contracts\* from the
| container; Lumen only registers the "url" service, not the contracts. Map the
| contracts to Lumen's implementations so helpers work across the app.
*/
$app->singleton(
\Illuminate\Contracts\Routing\ResponseFactory::class,
function () {
return new \Laravel\Lumen\Http\ResponseFactory();
}
);
$app->singleton(
\Illuminate\Contracts\Routing\UrlGenerator::class,
function ($app) {
return $app->make('url');
}
);
$app->withFacades(); $app->withFacades();
$app->withEloquent(); $app->withEloquent();
@@ -60,11 +87,15 @@ $app->singleton(
*/ */
$app->configure('app'); $app->configure('app');
$app->configure('logging');
$app->configure('logviewer');
$app->configure('tinker'); $app->configure('tinker');
$app->configure('tennant_master'); $app->configure('tennant_database');
$app->configure('report'); $app->configure('report');
$app->configure('app_parameter'); $app->configure('app_parameter');
$app->configure('parameter');
$app->configure('whatsapp');
$app->configure('kaunter');
/* /*
|-------------------------------------------------------------------------- |--------------------------------------------------------------------------
| Register Middleware | Register Middleware
@@ -80,9 +111,9 @@ $app->configure('app_parameter');
// App\Http\Middleware\ExampleMiddleware::class // App\Http\Middleware\ExampleMiddleware::class
// ]); // ]);
// $app->routeMiddleware([ $app->routeMiddleware([
// 'auth' => App\Http\Middleware\Authenticate::class, 'logviewer.password' => App\Http\Middleware\LogViewerPassword::class,
// ]); ]);
/* /*
|-------------------------------------------------------------------------- |--------------------------------------------------------------------------
+5 -2
View File
@@ -1,6 +1,9 @@
<?php <?php
return [ return [
'url' => env('APP_URL', url('/')), 'url' => env('APP_URL', 'http://localhost'),
'api_arrahnbid' => env('API_ARRAHNBID', 'http://lelong.test/api/') 'api_arrahnbid' => env('API_ARRAHNBID', 'http://lelong.test/api/'),
'api_arrahnbid_annur' => env('API_ARRAHNBID_ANNUR', env('API_ARRAHNBID', 'http://lelong.test/api/')),
'api_v3' => env('API_V3', 'http://apiv3.localhost/api/')
]; ];
+7
View File
@@ -0,0 +1,7 @@
<?php
return [
'url' => env('KAUNTER_URL', ''),
'notification_secret' => env('INTERNAL_NOTIFICATION_SECRET', ''),
'notification_timeout' => (int) env('KAUNTER_NOTIFICATION_TIMEOUT', 3),
];
+103
View File
@@ -0,0 +1,103 @@
<?php
use Monolog\Handler\NullHandler;
use Monolog\Handler\StreamHandler;
use Monolog\Handler\SyslogUdpHandler;
return [
/*
|--------------------------------------------------------------------------
| Default Log Channel
|--------------------------------------------------------------------------
|
| This option defines the default log channel that gets used when writing
| messages to the logs. The name specified in this option should match
| one of the channels defined in the "channels" configuration array.
|
*/
'default' => env('LOG_CHANNEL', 'stack'),
/*
|--------------------------------------------------------------------------
| Log Channels
|--------------------------------------------------------------------------
|
| Here you may configure the log channels for your application. Out of
| the box, Laravel uses the Monolog PHP logging library. This gives
| you a variety of powerful log handlers / formatters to utilize.
|
| Available Drivers: "single", "daily", "slack", "syslog",
| "errorlog", "monolog", "custom", "stack"
|
*/
'channels' => [
'stack' => [
'driver' => 'stack',
'channels' => ['single'],
'ignore_exceptions' => false,
],
'single' => [
'driver' => 'single',
'path' => storage_path('logs/laravel.log'),
'level' => env('LOG_LEVEL', 'debug'),
],
'daily' => [
'driver' => 'daily',
'path' => storage_path('logs/laravel.log'),
'level' => env('LOG_LEVEL', 'debug'),
'days' => 14,
],
'slack' => [
'driver' => 'slack',
'url' => env('LOG_SLACK_WEBHOOK_URL'),
'username' => 'Laravel Log',
'emoji' => ':boom:',
'level' => env('LOG_LEVEL', 'critical'),
],
'papertrail' => [
'driver' => 'monolog',
'level' => env('LOG_LEVEL', 'debug'),
'handler' => SyslogUdpHandler::class,
'handler_with' => [
'host' => env('PAPERTRAIL_URL'),
'port' => env('PAPERTRAIL_PORT'),
],
],
'stderr' => [
'driver' => 'monolog',
'handler' => StreamHandler::class,
'formatter' => env('LOG_STDERR_FORMATTER'),
'with' => [
'stream' => 'php://stderr',
],
],
'syslog' => [
'driver' => 'syslog',
'level' => env('LOG_LEVEL', 'debug'),
],
'errorlog' => [
'driver' => 'errorlog',
'level' => env('LOG_LEVEL', 'debug'),
],
'null' => [
'driver' => 'monolog',
'handler' => NullHandler::class,
],
'emergency' => [
'path' => storage_path('logs/laravel.log'),
],
],
];
+16
View File
@@ -0,0 +1,16 @@
<?php
return [
'password' => env('LOGVIEWER_PASSWORD'),
/*
|--------------------------------------------------------------------------
| Pattern and storage path settings
|--------------------------------------------------------------------------
|
| The env key for pattern and storage path with a default value
|
*/
'max_file_size' => 52428800, // size in Byte
'pattern' => env('LOGVIEWER_PATTERN', '*.log'),
'storage_path' => env('LOGVIEWER_STORAGE_PATH', storage_path('logs')),
];
+5
View File
@@ -0,0 +1,5 @@
<?php
return [
'max_mutuemas' => env('MAX_MUTUEMAS', true),
];
+6
View File
@@ -0,0 +1,6 @@
<?php
return [
'master_db' => env('TENNANT_MASTER_DB','online_arrahn'),
'kaunter_db' => env('TENNANT_KAUNTER_DB','kaunterpkb')
];
-5
View File
@@ -1,5 +0,0 @@
<?php
return [
'database' => env('TENNANT_MASTER_DB','master_erahn')
];
+12
View File
@@ -0,0 +1,12 @@
<?php
return [
'whatsapp_cloud_enabled' => env('WHATSAPP_CLOUD_ENABLED', true),
'token' => env('WHATSAPP_TOKEN'),
'phone_number_id' => env('WHATSAPP_PHONE_NUMBER_ID'),
'api_version' => env('WHATSAPP_API_VERSION', 'v25.0'),
'template' => env('WHATSAPP_TEMPLATE', 'hello_world'),
'template_lang' => env('WHATSAPP_TEMPLATE_LANG', 'en_US'),
'verify_token' => env('WHATSAPP_VERIFY_TOKEN'),
'app_secret' => env('WHATSAPP_APP_SECRET'),
];
@@ -42,7 +42,7 @@ class AddColumnsToKomuditiTransaksi extends Migration
{ {
$online_arrahn_connection_array = array_filter(config('database.connections'), function($connection) { $online_arrahn_connection_array = array_filter(config('database.connections'), function($connection) {
if($connection['database'] === 'online_arrahn' || $connection['database'] === 'master_krk' || $connection['database'] === config('tennant_master.database')){ if($connection['database'] === config('tennant_database.master_db')){
return true; return true;
} }
@@ -53,7 +53,7 @@ class AddColumnsToKomuditiTransaksi extends Migration
if(empty($online_arrahn_connection_array)){ if(empty($online_arrahn_connection_array)){
throw new Exception("online_arrahn or master_krk doesn't exist in config.database.connections array"); throw new Exception("Tennant master database (" . config('tennant_database.master_db') . ") doesn't exist in config.database.connections array");
} }
return array_keys($online_arrahn_connection_array)[0]; return array_keys($online_arrahn_connection_array)[0];
@@ -69,10 +69,10 @@ class AddNmJbgUntungPembiayaanColumnsToPalsuTable extends Migration
// Add index and foreign key constraint to existing norujukan column // Add index and foreign key constraint to existing norujukan column
if (Schema::connection($dbase)->hasColumn('palsu', 'norujukan')) { if (Schema::connection($dbase)->hasColumn('palsu', 'norujukan')) {
// Add index to norujukan column for better performance // Add index to norujukan column for better performance
$table->index('norujukan'); // $table->index('norujukan');
// Add foreign key constraint named 'norujukan' // Add foreign key constraint named 'norujukan'
$table->foreign('norujukan', 'norujukan')->references('norujukan')->on('gadai'); // $table->foreign('norujukan', 'norujukan')->references('norujukan')->on('gadai');
} }
}); });
@@ -87,21 +87,21 @@ class AddNmJbgUntungPembiayaanColumnsToPalsuTable extends Migration
Schema::connection($dbase)->table('palsu', function (Blueprint $table) use ($dbase) { Schema::connection($dbase)->table('palsu', function (Blueprint $table) use ($dbase) {
// Drop foreign key constraint and index from norujukan column // Drop foreign key constraint and index from norujukan column
if (Schema::connection($dbase)->hasColumn('palsu', 'norujukan')) { // if (Schema::connection($dbase)->hasColumn('palsu', 'norujukan')) {
try { // try {
$table->dropForeign('norujukan'); // $table->dropForeign('norujukan');
echo "Dropped foreign key 'norujukan' on connection '{$dbase}'\n"; // echo "Dropped foreign key 'norujukan' on connection '{$dbase}'\n";
} catch (\Exception $e) { // } catch (\Exception $e) {
echo "Warning: Could not drop foreign key 'norujukan' on connection '{$dbase}': " . $e->getMessage() . "\n"; // echo "Warning: Could not drop foreign key 'norujukan' on connection '{$dbase}': " . $e->getMessage() . "\n";
} // }
try { // try {
$table->dropIndex(['norujukan']); // $table->dropIndex(['norujukan']);
echo "Dropped index on 'norujukan' column on connection '{$dbase}'\n"; // echo "Dropped index on 'norujukan' column on connection '{$dbase}'\n";
} catch (\Exception $e) { // } catch (\Exception $e) {
echo "Warning: Could not drop index on 'norujukan' on connection '{$dbase}': " . $e->getMessage() . "\n"; // echo "Warning: Could not drop index on 'norujukan' on connection '{$dbase}': " . $e->getMessage() . "\n";
} // }
} // }
// Drop other columns if they exist // Drop other columns if they exist
$columnsToCheck = ['nilaimarhun', 'jbg', 'untung','untungonepercent','untungcajlain', 'pembiayaan']; $columnsToCheck = ['nilaimarhun', 'jbg', 'untung','untungonepercent','untungcajlain', 'pembiayaan'];
@@ -0,0 +1,57 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
use Illuminate\Support\Facades\DB;
class CreatePampasanTable extends Migration
{
private function getActiveDB(): array
{
$config_db = array_keys(config('database.connections'));
$db_connection = array_filter($config_db, function ($connection) {
try {
if ($connection === 'mysql7') return false; // ikut pattern sedia ada
DB::connection($connection)->select('SELECT 1');
return true;
} catch (\Exception $e) {
return false;
}
});
return $db_connection ? array_values($db_connection) : [];
}
public function up()
{
foreach ($this->getActiveDB() as $dbase) {
if (!Schema::connection($dbase)->hasTable('pampasan')) {
Schema::connection($dbase)->create('pampasan', function (Blueprint $table) {
$table->bigIncrements('id');
$table->string('norujukan', 50)->unique()->index();
$table->string('baucerno', 30)->index();
$table->string('kodcaw', 20)->index();
$table->decimal('jumlah_pampasan', 11, 2);
if (Schema::getConnection()->getPdo()->getAttribute(PDO::ATTR_SERVER_VERSION) >= '5.7') {
$table->json('denominasi')->nullable();
} else {
$table->longText('denominasi')->nullable();
}
$table->string('teller', 100);
$table->tinyInteger('status')
->default(0)
->comment('0 = belum dituntut, 1 = dituntut');
$table->timestamps();
});
}
}
}
public function down()
{
foreach ($this->getActiveDB() as $dbase) {
Schema::connection($dbase)->dropIfExists('pampasan');
}
}
}
@@ -0,0 +1,68 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
use Illuminate\Support\Facades\DB;
class AddJenisColumnToPalsuTable extends Migration
{
/**
* Get active database connections
*/
private function getActiveDB(): array
{
$config_db = array_keys(config("database.connections"));
$db_connection = array_filter($config_db, function($connection) {
try {
if ($connection == 'mysql7') {
return false;
}
DB::connection($connection)->select('SELECT 1');
return true;
} catch (\Exception $e) {
return false;
}
});
return $db_connection ? array_values($db_connection) : [];
}
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
$db_connection = $this->getActiveDB();
foreach ($db_connection as $dbase) {
Schema::connection($dbase)->table('palsu', function (Blueprint $table) use ($dbase) {
if (!Schema::connection($dbase)->hasColumn('palsu', 'jenis')) {
$table->string('jenis', 50)->nullable()->comment('Jenis/Type classification');
}
});
}
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
$db_connection = $this->getActiveDB();
foreach ($db_connection as $dbase) {
Schema::connection($dbase)->table('palsu', function (Blueprint $table) use ($dbase) {
if (Schema::connection($dbase)->hasColumn('palsu', 'jenis')) {
$table->dropColumn('jenis');
}
});
}
}
}
@@ -0,0 +1,78 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
use Illuminate\Support\Facades\DB;
class UpdateJenisToPampasanForSempornaRecords extends Migration
{
/**
* Semporna norujukan records to update
*/
private function getSempornaRecords(): array
{
return [
'011237240808-0003',
'011237240719-0015',
'011237240806-0011',
'011237240828-0001',
'011237240904-0007',
'011237240904-0008',
'011237240904-0009',
'011237240719-0023',
'011237240719-0024',
'011237240719-0025',
'011237240618-0026',
'011237240719-0027',
'011237240719-0028',
'011237240618-0020',
'011237240719-0030',
'011237240618-0029',
'011237240731-0026',
'011237240912-0009'
];
}
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
$semporna_records = $this->getSempornaRecords();
// Update jenis to 'pampasan' for Semporna records in mysql34 (Semporna branch)
try {
$updated = DB::connection('mysql34')->table('palsu')
->whereIn('norujukan', $semporna_records)
->update(['jenis' => 'pampasan']);
echo "Updated {$updated} Semporna records with jenis = 'pampasan'\n";
} catch (\Exception $e) {
echo "Error updating Semporna records: " . $e->getMessage() . "\n";
}
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
$semporna_records = $this->getSempornaRecords();
// Revert jenis to null for Semporna records
try {
$reverted = DB::connection('mysql34')->table('palsu')
->whereIn('norujukan', $semporna_records)
->update(['jenis' => null]);
echo "Reverted {$reverted} Semporna records jenis to null\n";
} catch (\Exception $e) {
echo "Error reverting Semporna records: " . $e->getMessage() . "\n";
}
}
}
@@ -0,0 +1,130 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
use Illuminate\Support\Facades\DB;
class UpdateNonSempornaRecordsJenisToHapuskira extends Migration
{
/**
* Get active database connections
*/
private function getActiveDB(): array
{
$config_db = array_keys(config("database.connections"));
$db_connection = array_filter($config_db, function($connection) {
try {
if ($connection == 'mysql7') {
return false;
}
DB::connection($connection)->select('SELECT 1');
return true;
} catch (\Exception $e) {
return false;
}
});
return $db_connection ? array_values($db_connection) : [];
}
/**
* Semporna norujukan records to exclude
*/
private function getSempornaRecords(): array
{
return [
'011237240808-0003',
'011237240719-0015',
'011237240806-0011',
'011237240828-0001',
'011237240904-0007',
'011237240904-0008',
'011237240904-0009',
'011237240719-0023',
'011237240719-0024',
'011237240719-0025',
'011237240618-0026',
'011237240719-0027',
'011237240719-0028',
'011237240618-0020',
'011237240719-0030',
'011237240618-0029',
'011237240731-0026',
'011237240912-0009'
];
}
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
$db_connection = $this->getActiveDB();
$semporna_records = $this->getSempornaRecords();
foreach ($db_connection as $dbase) {
try {
if ($dbase == 'mysql34') {
// For Semporna (mysql34), update only non-Semporna records to 'hapuskira'
$updated = DB::connection($dbase)->table('palsu')
->whereNotIn('norujukan', $semporna_records)
->update(['jenis' => 'hapuskira']);
if ($updated > 0) {
echo "Updated {$updated} non-Semporna records in {$dbase} to jenis = 'hapuskira'\n";
}
} else {
// For all other databases, update all records to 'hapuskira'
$updated = DB::connection($dbase)->table('palsu')
->update(['jenis' => 'hapuskira']);
if ($updated > 0) {
echo "Updated {$updated} records in {$dbase} to jenis = 'hapuskira'\n";
}
}
} catch (\Exception $e) {
echo "Error updating {$dbase}: " . $e->getMessage() . "\n";
}
}
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
$db_connection = $this->getActiveDB();
foreach ($db_connection as $dbase) {
try {
// Revert all jenis values to null except Semporna records which should remain 'pampasan'
if ($dbase == 'mysql34') {
$semporna_records = $this->getSempornaRecords();
$reverted = DB::connection($dbase)->table('palsu')
->whereNotIn('norujukan', $semporna_records)
->update(['jenis' => null]);
if ($reverted > 0) {
echo "Reverted {$reverted} non-Semporna records in {$dbase} jenis to null\n";
}
} else {
$reverted = DB::connection($dbase)->table('palsu')
->update(['jenis' => null]);
if ($reverted > 0) {
echo "Reverted {$reverted} records in {$dbase} jenis to null\n";
}
}
} catch (\Exception $e) {
echo "Error reverting {$dbase}: " . $e->getMessage() . "\n";
}
}
}
}
@@ -0,0 +1,73 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
use Illuminate\Support\Facades\DB;
class AddStatusColumnToPalsuTable extends Migration
{
/**
* Get active database connections
*/
private function getActiveDB(): array
{
$config_db = array_keys(config("database.connections"));
$db_connection = array_filter($config_db, function($connection) {
try {
if ($connection == 'mysql7') {
return false;
}
DB::connection($connection)->select('SELECT 1');
return true;
} catch (\Exception $e) {
return false;
}
});
return $db_connection ? array_values($db_connection) : [];
}
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
$db_connection = $this->getActiveDB();
foreach ($db_connection as $dbase) {
Schema::connection($dbase)->table('palsu', function (Blueprint $table) use ($dbase) {
if (!Schema::connection($dbase)->hasColumn('palsu', 'status')) {
$table->unsignedSmallInteger('status')->default(0)->comment('Status value');
}
});
// Update existing rows to have status = 0
DB::connection($dbase)->table('palsu')
->whereNull('status')
->update(['status' => 0]);
}
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
$db_connection = $this->getActiveDB();
foreach ($db_connection as $dbase) {
Schema::connection($dbase)->table('palsu', function (Blueprint $table) use ($dbase) {
if (Schema::connection($dbase)->hasColumn('palsu', 'status')) {
$table->dropColumn('status');
}
});
}
}
}
@@ -0,0 +1,80 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
use Illuminate\Support\Facades\DB;
class UpdateAllPalsuStatusToOne extends Migration
{
/**
* Get active database connections
*/
private function getActiveDB(): array
{
$config_db = array_keys(config("database.connections"));
$db_connection = array_filter($config_db, function($connection) {
try {
if ($connection == 'mysql7') {
return false;
}
DB::connection($connection)->select('SELECT 1');
return true;
} catch (\Exception $e) {
return false;
}
});
return $db_connection ? array_values($db_connection) : [];
}
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
$db_connection = $this->getActiveDB();
foreach ($db_connection as $dbase) {
try {
// Update all status values to 1 in palsu table
$updated = DB::connection($dbase)->table('palsu')
->update(['status' => 1]);
if ($updated > 0) {
echo "Updated {$updated} records in {$dbase} palsu table to status = 1\n";
}
} catch (\Exception $e) {
echo "Error updating {$dbase}: " . $e->getMessage() . "\n";
}
}
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
$db_connection = $this->getActiveDB();
foreach ($db_connection as $dbase) {
try {
// Revert all status values back to 0 in palsu table
$reverted = DB::connection($dbase)->table('palsu')
->update(['status' => 0]);
if ($reverted > 0) {
echo "Reverted {$reverted} records in {$dbase} palsu table to status = 0\n";
}
} catch (\Exception $e) {
echo "Error reverting {$dbase}: " . $e->getMessage() . "\n";
}
}
}
}
@@ -0,0 +1,78 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
use Illuminate\Support\Facades\DB;
class UpdateSempornaRecordsStatusToZero extends Migration
{
/**
* Semporna norujukan records to update status to 0
*/
private function getSempornaRecords(): array
{
return [
'011237240808-0003',
'011237240719-0015',
'011237240806-0011',
'011237240828-0001',
'011237240904-0007',
'011237240904-0008',
'011237240904-0009',
'011237240719-0023',
'011237240719-0024',
'011237240719-0025',
'011237240618-0026',
'011237240719-0027',
'011237240719-0028',
'011237240618-0020',
'011237240719-0030',
'011237240618-0029',
'011237240731-0026',
'011237240912-0009'
];
}
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
$semporna_records = $this->getSempornaRecords();
// Update status to 0 for Semporna records in mysql34 (Semporna branch)
try {
$updated = DB::connection('mysql34')->table('palsu')
->whereIn('norujukan', $semporna_records)
->update(['status' => 0]);
echo "Updated {$updated} Semporna records with status = 0\n";
} catch (\Exception $e) {
echo "Error updating Semporna records status: " . $e->getMessage() . "\n";
}
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
$semporna_records = $this->getSempornaRecords();
// Revert status to 1 for Semporna records
try {
$reverted = DB::connection('mysql34')->table('palsu')
->whereIn('norujukan', $semporna_records)
->update(['status' => 1]);
echo "Reverted {$reverted} Semporna records status to 1\n";
} catch (\Exception $e) {
echo "Error reverting Semporna records status: " . $e->getMessage() . "\n";
}
}
}
@@ -0,0 +1,60 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
use Illuminate\Support\Facades\DB;
class AddAgreementPrintedAtToPampasanTable extends Migration
{
/**
* Get active database connections
*/
private function getActiveDB(): array
{
$config_db = array_keys(config("database.connections"));
$db_connection = array_filter($config_db, function($connection) {
try {
if ($connection === 'mysql7') return false; // ikut pattern sedia ada
DB::connection($connection)->select('SELECT 1');
return true;
} catch (\Exception $e) {
return false;
}
});
return $db_connection ? array_values($db_connection) : [];
}
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
foreach ($this->getActiveDB() as $dbase) {
Schema::connection($dbase)->table('pampasan', function (Blueprint $table) use ($dbase) {
if (!Schema::connection($dbase)->hasColumn('pampasan', 'agreement_printed_at')) {
$table->timestamp('agreement_printed_at')->nullable()->comment('Timestamp when agreement was printed');
}
});
}
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
foreach ($this->getActiveDB() as $dbase) {
Schema::connection($dbase)->table('pampasan', function (Blueprint $table) use ($dbase) {
if (Schema::connection($dbase)->hasColumn('pampasan', 'agreement_printed_at')) {
$table->dropColumn('agreement_printed_at');
}
});
}
}
}
@@ -0,0 +1,83 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Schema;
class AddTHtrAgToSerahbakiTable extends Migration
{
/**
* Run the migrations.
*
* @return void
*/
protected $db_connection;
public function getActiveDB()
{
$config_db = array_keys(config('database.connections'));
return array_filter($config_db, function ($connection) {
$config = config("database.connections.$connection");
// Skip if host is empty
if (empty($config['host'])) return false;
try {
DB::connection($connection)->getPdo();
return true;
} catch (\Exception $e) {
return false;
}
});
}
public function up()
{
$db_connection = $this->getActiveDB();
$key = array_search('mysql7', $db_connection);
if ($key !== false) {
unset($db_connection[$key]);
}
foreach ($db_connection as $dbase) {
Schema::connection($dbase)->table('serahbaki', function (Blueprint $table) use ($dbase) {
if (!Schema::connection($dbase)->hasColumn('serahbaki', 't_htr_ag')) {
$table->date('t_htr_ag')->nullable()->after('aktif');
}
});
}
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
$db_connection = $this->getActiveDB();
$key = array_search('mysql7', $db_connection);
if ($key !== false) {
unset($db_connection[$key]);
}
foreach ($db_connection as $dbase) {
if (Schema::connection($dbase)->hasColumn('serahbaki', 't_htr_ag')) {
Schema::connection($dbase)->table('serahbaki', function (Blueprint $table) {
$table->dropColumn('t_htr_ag');
});
}
}
}
}
@@ -0,0 +1,40 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
class CreateWtdSimulasiTable extends Migration
{
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
Schema::create('wtd_simulasi', function (Blueprint $table) {
$table->id();
$table->string('bulan');
$table->string('tahun');
$table->string('kodcaw');
$table->integer('jumlah_sag');
$table->decimal('pembiayaan', 15, 2);
$table->decimal('baki', 15, 2);
$table->integer('simulasi');
$table->timestamps();
});
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
Schema::dropIfExists('wtd_simulasi');
}
}

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