diff --git a/app/Console/Kernel.php b/app/Console/Kernel.php index ad1e238..5c7d714 100644 --- a/app/Console/Kernel.php +++ b/app/Console/Kernel.php @@ -5,9 +5,7 @@ namespace App\Console; use Illuminate\Console\Scheduling\Schedule; use Laravel\Lumen\Console\Kernel as ConsoleKernel; -use App\Cawangan; -use App\Gadai; -use Carbon\Carbon; +use App\Jobs\WhatsappUnsoldCommodityScanner; class Kernel extends ConsoleKernel { @@ -34,5 +32,7 @@ class Kernel extends ConsoleKernel // $schedule->command('gadai:daily')->daily()->timezone('Asia/Kuala_Lumpur')->at('00:00'); + + $schedule->job(new WhatsappUnsoldCommodityScanner)->daily()->timezone('Asia/Kuala_Lumpur')->at('00:00'); } } diff --git a/app/Http/Controllers/SettingController.php b/app/Http/Controllers/SettingController.php new file mode 100644 index 0000000..bf9476a --- /dev/null +++ b/app/Http/Controllers/SettingController.php @@ -0,0 +1,130 @@ +get(); + + return response()->json($settings); + } + + public function updateUnsoldCommodityNotifications(Request $request) + { + $request_array = $request->input(); + + $general_inputs = array_filter( + $request_array, + function ($value, $key) { + return strpos($key, 'pic_') === false; + }, + ARRAY_FILTER_USE_BOTH + ); + + foreach ($general_inputs as $key => $value) { + Setting::where([ + ['group', 'unsold_commodity_notifications'], + ['key', $key] + ]) + ->first() + ->update(['value' => $value]); + } + + $pic_inputs = array_filter( + $request_array, + function ($value, $key) { + return Str::startsWith($key, 'pic_'); + }, + ARRAY_FILTER_USE_BOTH + ); + + $unique_pic_input = array_map(function ($array, $key) { + return $this->filterUniqueById($array, $key); + }, $pic_inputs, array_keys($pic_inputs)); + + $transformed_unique_pic_input = []; + + array_walk($unique_pic_input, function ($item) use (&$transformed_unique_pic_input) { + foreach ($item as $key => $value) { + + if(count($value) === 0){ + $value = [new \stdClass()]; + } + + $transformed_unique_pic_input[$key] = $value; + } + }); + + + foreach ($transformed_unique_pic_input as $key => $value) { + Setting::where([ + ['group', 'unsold_commodity_notifications'], + ['key', $key] + ]) + ->first() + ->update(['value' => json_encode($value)]); + } + + $this->cancelPreviousCommodityNotificationsJobs(); + + dispatch((new WhatsappUnsoldCommodityScanner())); + + return response()->json('success'); + } + + + public function filterUniqueById($array, $key) + { + $uniqueIds = []; + $filteredArray = []; + + if ($array !== []) { + foreach ($array as $item) { + if (!in_array($item['id'], $uniqueIds)) { + $uniqueIds[] = $item['id']; + $filteredArray[] = $item; + } + } + } + + return [ + $key => $filteredArray + ]; + } + + + public function cancelPreviousCommodityNotificationsJobs() + { + // flushed the fail job in queueu + Artisan::call('queue:flush'); + + $getClassNameString = function ($className) { + $name = explode("\\", $className); + return end($name); + }; + + $commodityNotificationClasses = [ + WhatsappUnsoldCommodityNotification::class, + WhatsappUnsoldCommodityScanner::class, + ]; + + + foreach ($commodityNotificationClasses as $class) { + DB::connection('mysql7') + ->table('jobs') + ->where('payload', 'like', '%' . $getClassNameString($class) . '%') + ->delete(); + } + } +} diff --git a/app/Jobs/WhatsappUnsoldCommodityNotification.php b/app/Jobs/WhatsappUnsoldCommodityNotification.php new file mode 100644 index 0000000..fe0dd51 --- /dev/null +++ b/app/Jobs/WhatsappUnsoldCommodityNotification.php @@ -0,0 +1,108 @@ +where('group', 'unsold_commodity_notifications')->get(); + $status = $settings->where('key', 'status')->first()->value; + $start_time = $settings->where('key', 'start_time')->first()->value; + $end_time = $settings->where('key', 'end_time')->first()->value; + $message = $settings->where('key', 'message')->first()->value; + $isAllKomoditiSold = KomuditiPurchase::on('mysql7')->latest()->first()->unit_komuditi === 0; + $isWabotCredentialNotComplete = env('WABOT_API') === null || env('WABOT_INSTANCES_ID') === null || env('WABOT_TOKEN_KEYS') === null; + + $pic_key = 'pic_' . strtolower(Carbon::now()->englishDayOfWeek); + $pic = json_decode($settings->where('key', $pic_key)->first()->value); + + $phone_numbers = array_map(function ($p) { + if (isset($p->no_telefon)) { + return $p->no_telefon; + } + }, $pic); + + if ($isWabotCredentialNotComplete) { + Log::error('Wabot credential not complete'); + return false; + } + + if ($phone_numbers[0] === NULL) { + Log::error('No PIC phone numbers detected'); + return false; + } + + if ($status === '0') { + Log::info('Unsold commodity notifications are turned off, no notification will be sent'); + return false; + } + + if (Carbon::parse($start_time) > Carbon::now()) { + return false; + } + + if (Carbon::parse($end_time) < Carbon::now()) { + return false; + } + + if ($isAllKomoditiSold) { + Log::info('All komoditi is sold'); + return false; + } + + + foreach ($phone_numbers as $phone_number) { + $response = Http::get(env('WABOT_API'), [ + 'number' => $phone_number, + 'type' => 'text', + 'message' => $message, + 'instance_id' => env('WABOT_INSTANCES_ID'), + 'access_token' => env('WABOT_TOKEN_KEYS') + ]); + + + //insert log blast wasap + $logblastwasap = new BlastWasap(); + $logblastwasap->kodcaw = 'OPERASI'; + $logblastwasap->notelefon = $phone_number; + $logblastwasap->norujukan = 'Notifikasi Komoditi Tidak Terjual'; + $logblastwasap->status = $response; + $logblastwasap->created_at = Carbon::now(); + $logblastwasap->updated_at = Carbon::now(); + $logblastwasap->save(); + + Log::info("WABOT - Notifikasi Komoditi Tidak Terjual" . $response); + } + + + + dispatch((new WhatsappUnsoldCommodityNotification($this->message))->delay(Carbon::now()->addMinutes(5))); + } +} diff --git a/app/Jobs/WhatsappUnsoldCommodityScanner.php b/app/Jobs/WhatsappUnsoldCommodityScanner.php new file mode 100644 index 0000000..61e46de --- /dev/null +++ b/app/Jobs/WhatsappUnsoldCommodityScanner.php @@ -0,0 +1,42 @@ +where('group', 'unsold_commodity_notifications')->get(); + $status = $settings->where('key', 'status')->first()->value; + $start_time = $settings->where('key', 'start_time')->first()->value; + + + if ($status === '0') { + return false; + } + + dispatch((new WhatsappUnsoldCommodityNotification($this->message))->delay(Carbon::parse($start_time))); + + } +} diff --git a/app/Setting.php b/app/Setting.php new file mode 100644 index 0000000..7bc5e32 --- /dev/null +++ b/app/Setting.php @@ -0,0 +1,19 @@ +router->group([ ], function ($router) { require __DIR__.'/../routes/web.php'; require __DIR__.'/../routes/report.php'; + require __DIR__.'/../routes/setting.php'; }); $app->middleware([ diff --git a/config/app.php b/config/app.php new file mode 100644 index 0000000..ca53786 --- /dev/null +++ b/config/app.php @@ -0,0 +1,5 @@ + env('APP_URL', url('/')) +]; diff --git a/config/database.php b/config/database.php index f464311..71542a5 100644 --- a/config/database.php +++ b/config/database.php @@ -5,6 +5,18 @@ return [ 'default' => 'mysql7', 'migrations' => 'migrations', 'connections' => [ + 'mysql' => [ + 'driver' => 'mysql', + 'host' => env('DB_HOST_7'), + 'port' => env('DB_PORT_7'), + 'database' => env('DB_DATABASE_7'), + 'username' => env('DB_USERNAME_7'), + 'password' => env('DB_PASSWORD_7'), + 'charset' => 'utf8', + 'collation' => 'utf8_unicode_ci', + 'prefix' => '', + 'strict' => false, + ], 'lelong' => [ 'driver' => 'mysql', 'host' => env('DB_HOST_LELONG'), diff --git a/database/migrations/2024_05_27_093206_create_settings_table.php b/database/migrations/2024_05_27_093206_create_settings_table.php new file mode 100644 index 0000000..f1edbaa --- /dev/null +++ b/database/migrations/2024_05_27_093206_create_settings_table.php @@ -0,0 +1,40 @@ +id(); + $table->string('group')->nullable(); + $table->string('key')->unique(); + $table->text('value')->nullable(); + $table->text('description')->nullable(); + $table->timestamps(); + }); + } + + // Call the seeder + (new UnsoldCommodityNotificationSettingSeeders())->run(); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + Schema::dropIfExists('settings'); + } +} diff --git a/database/migrations/arrahn_master_db_202405160953.json b/database/migrations/arrahn_master_db_202405160953.json new file mode 100644 index 0000000..ab3e6ca --- /dev/null +++ b/database/migrations/arrahn_master_db_202405160953.json @@ -0,0 +1,139 @@ +{ +"arrahn_master_db": [ + { + "details_caw" : "Kota Bharu 2", + "kodcaw" : "KB2" + }, + { + "details_caw" : "Wakaf Che Yeh", + "kodcaw" : "WCY" + }, + { + "details_caw" : "1 Stop", + "kodcaw" : "1STOP" + }, + { + "details_caw" : "Jelawat", + "kodcaw" : "020301" + }, + { + "details_caw" : "Wakaf Bharu", + "kodcaw" : "WB" + }, + { + "details_caw" : "Kok Lanas", + "kodcaw" : "ALS" + }, + { + "details_caw" : "Pasir Puteh", + "kodcaw" : "020306" + }, + { + "details_caw" : "Machang", + "kodcaw" : "ARM" + }, + { + "details_caw" : "Pasir Mas", + "kodcaw" : "APM" + }, + { + "details_caw" : "Gua Musang", + "kodcaw" : "010311" + }, + { + "details_caw" : "Guchil", + "kodcaw" : "GC" + }, + { + "details_caw" : "Jeli", + "kodcaw" : "JLI" + }, + { + "details_caw" : "Rantau Panjang", + "kodcaw" : "ARP" + }, + { + "details_caw" : "Kuantan", + "kodcaw" : "010621" + }, + { + "details_caw" : "Pasir Gudang", + "kodcaw" : "010136" + }, + { + "details_caw" : "Skudai", + "kodcaw" : "011235" + }, + { + "details_caw" : "Putatan", + "kodcaw" : "011227" + }, + { + "details_caw" : "Bentong", + "kodcaw" : "010620" + }, + { + "details_caw" : "Raub", + "kodcaw" : "010617" + }, + { + "details_caw" : "Kangar", + "kodcaw" : "010915" + }, + { + "details_caw" : "Sandakan", + "kodcaw" : "011228" + }, + { + "details_caw" : "Sungai Petani", + "kodcaw" : "010219" + }, + { + "details_caw" : "Tawau", + "kodcaw" : "011229" + }, + { + "details_caw" : "Api-Api", + "kodcaw" : "011230" + }, + { + "details_caw" : "Kajang", + "kodcaw" : "011013" + }, + { + "details_caw" : "Raja Laut", + "kodcaw" : "011412" + }, + { + "details_caw" : "Beaufort", + "kodcaw" : "011231" + }, + { + "details_caw" : "Kota Belud", + "kodcaw" : "011232" + }, + { + "details_caw" : "Tuaran", + "kodcaw" : "011234" + }, + { + "details_caw" : "Keningau", + "kodcaw" : "011233" + }, + { + "details_caw" : "Tanah Merah", + "kodcaw" : "020303" + }, + { + "details_caw" : "Temerloh", + "kodcaw" : "010618" + }, + { + "details_caw" : "Semporna", + "kodcaw" : "011237" + }, + { + "details_caw" : "Kota Bharu 1", + "kodcaw" : "KB1" + } +]} diff --git a/database/seeds/UnsoldCommodityNotificationSettingsSeeders.php b/database/seeds/UnsoldCommodityNotificationSettingsSeeders.php new file mode 100644 index 0000000..9bfab95 --- /dev/null +++ b/database/seeds/UnsoldCommodityNotificationSettingsSeeders.php @@ -0,0 +1,91 @@ +each(fn($x) => $x->delete()); + + $data = [ + [ + 'key' => 'status', + 'value' => '1', + 'group' => 'unsold_commodity_notifications', + 'description' => 'Turn on or turn off notification for unsold commodity notifications', + ], + [ + 'key' => 'start_time', + 'value' => '20:00', + 'group' => 'unsold_commodity_notifications', + 'description' => 'The time the notifications start', + ], + [ + 'key' => 'end_time', + 'value' => '23:00', + 'group' => 'unsold_commodity_notifications', + 'description' => 'The time the notifications end', + ], + [ + 'key' => 'message', + 'value' => 'Baki komoditi masih lagi berbaki dan belum habis dijual', + 'group' => 'unsold_commodity_notifications', + 'description' => 'Turn on or turn off notification for unsold commodity notifications', + ], + [ + 'key' => 'pic_sunday', + 'value' => '[{}]', + 'group' => 'unsold_commodity_notifications', + 'description' => 'Person Incharge on Sunday', + ], + [ + 'key' => 'pic_monday', + 'value' => '[{}]', + 'group' => 'unsold_commodity_notifications', + 'description' => 'Person Incharge on Monday', + ], + [ + 'key' => 'pic_tuesday', + 'value' => '[{}]', + 'group' => 'unsold_commodity_notifications', + 'description' => 'Person Incharge on Tuesday', + ], + [ + 'key' => 'pic_wednesday', + 'value' => '[{}]', + 'group' => 'unsold_commodity_notifications', + 'description' => 'Person Incharge on Wednesday', + ], + [ + 'key' => 'pic_thursday', + 'value' => '[{}]', + 'group' => 'unsold_commodity_notifications', + 'description' => 'Person Incharge on Thursday', + ], + [ + 'key' => 'pic_friday', + 'value' => '[{}]', + 'group' => 'unsold_commodity_notifications', + 'description' => 'Person Incharge on Friday', + ], + [ + 'key' => 'pic_saturday', + 'value' => '[{}]', + 'group' => 'unsold_commodity_notifications', + 'description' => 'Person Incharge on Saturday', + ], + + ]; + + array_walk($data, function ($setting) { + Setting::create($setting); + }); + } +} diff --git a/routes/setting.php b/routes/setting.php new file mode 100644 index 0000000..e4e7a2f --- /dev/null +++ b/routes/setting.php @@ -0,0 +1,6 @@ +group(['prefix' => 'api/settings'], function () use ($router) { + $router->get('unsold-commodity-notifications', ['uses' => 'SettingController@getUnsoldCommodityNotifications']); + $router->post('unsold-commodity-notifications', ['uses' => 'SettingController@updateUnsoldCommodityNotifications']); +});