DONE: update .env for production

This commit is contained in:
ISMAIL MASSERAN
2026-09-24 11:26:29 +08:00
parent 8fc7545ca2
commit 0c404eda5b
6 changed files with 287 additions and 186 deletions
+10 -171
View File
@@ -87,182 +87,21 @@ DB_DATABASE_11=arrahn_pputeh
DB_USERNAME_11=spider
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
QUEUE_CONNECTION=sync
MAX_MUTUEMAS=true
WABOT_API=https://md.wabot.my/api/send.php
WABOT_INSTANCES_ID=63F40BD120DB4
# WABOT_INSTANCES_ID=64892FD7440A6
WABOT_TOKEN_KEYS=cbee7e95cf3ffbfa0531d5fddfd44f87
TENNANT_MASTER_DB=master_erahn
TENNANT_KAUNTER_DB=kaunter_erahn
# Meta WhatsApp Cloud (test number). Paste token locally; do not commit it.
WHATSAPP_TOKEN=
KAUNTER_URL=http://host.docker.internal:8081
INTERNAL_NOTIFICATION_SECRET=
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
ONEWAYSMS_API=http://gateway.onewaysms.com.my:10001/api.aspx
ONEWAYSMS_AUTH_USER=APIUK330HDAFO
ONEWAYSMS_AUTH_PASS=APIUK330HDAFOUK330
ADMIN_PHONE_NUMBER=60193450165
ACTIVE_JOB_SERVER=false
# Kaunter inbox (PC modal request → operasi bell). Same secret as kaunter INTERNAL_NOTIFICATION_SECRET.
KAUNTER_URL=http://host.docker.internal:8081
INTERNAL_NOTIFICATION_SECRET=
WHATSAPP_VERIFY_TOKEN= # webhook verify token
WHATSAPP_APP_SECRET= # X-Hub-Signature-256 checks; need to be enable first
ADMIN_PHONE_NUMBER=60193450165
+22 -2
View File
@@ -59,9 +59,29 @@ DB_DATABASE_7=master_erahn
DB_USERNAME_7=spider
DB_PASSWORD_7=arrahn@123
MAX_MUTUEMAS=true
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
TENNANT_MASTER_DB=master_erahn
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_TOKEN=EAAZAonT56AO0BSlxZAKa8QX6HIWJpp5Czsz2KQ8BYE4iyZAe5fg8ZAmaSwZCXZCPf44xazDZAhaXLHJKHKUrUZCxei86EWl6Ar3RingfybZAlXp79Yd6WwOG5IZAnu9o5mevm895ygrs39H11G01fpYU2lYRpIWdn6URkTA0kMJdqZAlTaRILTjUM5KhvV05Q4lLAZDZD
WHATSAPP_PHONE_NUMBER_ID=1323449077519027
WHATSAPP_API_VERSION=v25.0
WHATSAPP_TEMPLATE=pembiayaan_online_paid
WHATSAPP_TEMPLATE_LANG=ms
WHATSAPP_VERIFY_TOKEN=418ed86d49422071681c76bed25ae1cb7e90456c794a92f1c9ea417945a35a0a
WHATSAPP_APP_SECRET=
ADMIN_PHONE_NUMBER=60193450165
+128 -13
View File
@@ -8,6 +8,7 @@ use App\Cawangan;
use App\Mohonid;
use App\MohonAnggota;
use App\Customer;
use App\Services\StaffNotificationClient;
use Carbon\Carbon;
@@ -444,6 +445,8 @@ public function create(REQUEST $request,$kodcaw,$norujukan,$roles)
$audit->updated_at = $harini;
$audit->save();
$this->notifyOperasiAssignAnggota($kodcaw, $cawangan, $kelulusan, $request);
// ✅ Return JSON response ke frontend
return response()->json([
'success' => true,
@@ -466,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
public function kepohonancreate(REQUEST $request,$kodcaw,$norujukan)
@@ -600,26 +655,86 @@ public function create(REQUEST $request,$kodcaw,$norujukan,$roles)
return response()->json($arraykelulusan,200);
}
public function listoperasikelulusan()
public function listoperasikelulusan(Request $request)
{
$harini = Carbon::now();
$harini = new Carbon;
$dateFrom = $request->query('date_from');
$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 = [];
foreach($cawangan_all as $index=>$cawangan){
$kelulusan=Mohon::on($cawangan['mysql'])
->where('peloperasi','=','operasi')
->where('operasi','!=','')
->get();
foreach ($cawangan_all as $cawangan) {
$query = Mohon::on($cawangan['mysql'])
->select([
'tarikh',
'norujukan',
'komen',
'jumpinj',
'nilaimarhun',
'berat',
'margin',
'status',
'operasi',
'masalulus',
])
->where('peloperasi', '=', 'operasi')
->where('operasi', '!=', '');
if(sizeof($kelulusan) != 0){
array_push($arraykelulusan,["kelulusanall" => $kelulusan,"cawangan" => $cawangan['details_caw'],"cawangankod" => $cawangan['kodcaw']]);
if ($dateFrom) {
$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){
@@ -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,
]);
}
}
}
}
}
+2
View File
@@ -6,4 +6,6 @@ return [
'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'),
];
+3
View File
@@ -699,6 +699,9 @@ $router->group(['prefix'=>'api'], function () use ($router){
$router->get('initiate/modal-online', ['uses' => 'ModalOnlineController@initiate']);
// Operasi kelulusan pembiayaan online (must be before {kodcaw} routes)
$router->get('whatsapp/webhook', ['uses' => 'WhatsappWebhookController@verify']);
$router->post('whatsapp/webhook', ['uses' => 'WhatsappWebhookController@handle']);
$router->get('pembiayaan-online/operasi/batches', ['uses' => 'PembiayaanOnlineController@operasiListBatches']);
$router->get('pembiayaan-online/operasi/{kodcaw}/batches/{batchId}', ['uses' => 'PembiayaanOnlineController@operasiShowBatch']);
$router->post('pembiayaan-online/operasi/{kodcaw}/lines/{id}/approve', ['uses' => 'PembiayaanOnlineController@operasiApproveLine']);