Akhdani Tech Talk 2021 Series #1 – Otomatisasi Pekerjaan Menggunakan Bot WhatsApp

Otomatisasi Pekerjaan Menggunakan Bot WhatsApp

Oleh: Gita Marshelina, Wiby Putra Adyan Ramdhani, Aria Enggar Pamungkas

Masalah dan Ide

WhatsApp hingga saat ini masih dipakai oleh semua anggota tim di lingkungan PT Akhdani Reka Solusi (ARS) sebagai media komunikasi. Bagaimana jika kita bisa memanfaatkan WhatsApp untuk lebih jauh lagi? Dalam lingkungan ARS pada pekerjaan HokBen Rework, bot WhatsApp mulai digunakan untuk otomatisasi pengecekan sumber daya server dan rekapitulasi pembayaran hanya dengan mengirim pesan tertentu pada jalur grup. Berdasarkan hal tersebut, kita bisa memanfaatkan bot ini sebagai portal untuk memudahkan pekerjaan kita yang berulang-ulang, seperti melihat rekap laporan harian (daily report), detail info proyek, hingga integrasi dengan tools lain seperti Trello atau Airtable untuk melihat status atau detil tugas yang diberikan.

Rencana Implementasi

1. Menggunakan Bot WhatsApp

Bot WhatsApp yang digunakan bukan dari API resmi WhatsApp, melainkan proyek open source dari

https://github.com/open-wa/wa-automate-nodejs

Instalasi library ini membutuhkan syarat berikut:

  • Kebutuhan Perangkat Keras
    1. Satu buah server, bisa sebuah PC/laptop ataupun VPS.
    2. Smartphone yang terkoneksi internet
  • Kebutuhan Perangkat Lunak
    1. NodeJS
    2. PHP
    3. Database
  • Tahapan Instalasi

Untuk instalasi sistem yang perlu dilakukan adalah:

  1. Instalasi dan konfigurasi library dan software yang diperlukan
  2. Membuat script sesuai kebutuhan
  3. Scan QR code
    2. Cara kerja sistem Bot WhatsApp

Pada dasarnya library NodeJS tersebut akan menggunakan headless Chromium yang dikendalikan oleh library ini. Dari mulai membuka WhatsApp web dan menampilkan QR code yang kemudian akan dipindai menggunakan smartphone yang sudah dipasang aplikasi WhatsApp.

1

Gambar 1. Cara Kerja Sistem Bot WhatsApp

Setelah login menggunakan QR berhasil, library ini akan otomatis membaca DOM teks pesan yang masuk, baik melalui grup maupun pribadi untuk kemudian dibaca konten pesan tersebut. Jika konten pesan ada yang cocok dengan kata kunci yang sudah didefinisikan, maka library ini akan meneruskan eksekusi kode sesuai yang telah dibuat sebelumnya. Berikut contoh kode eksekusi yang telah dibuat:

2

Gambar 2. Contoh Kode

3. Skrip BOT Dinamis

Skrip bot yang dinamis akan membuat bot WhatsApp bisa menerima masukan dan mengerjakan tugas yang lebih beragam dan bisa ditambah sewaktu-waktu, untuk skrip ini direncanakan akan dibuat dalam bahasa pemrograman PHP. Untuk pengelolaan skripnya akan dibuatkan aplikasi web sebagai admin panel.

3

Gambar 3. Contoh Tampilan Halaman Index Admin Panel

4

Gambar 4. Contoh Tampilan Halaman Tambah Script 

4. Contoh Integrasi dengan Tools Lain
  • Trello dan Airtable

Trello dan Airtable keduanya menyediakan API untuk bisa diakses via HTTP Request.  Untuk info lebih lanjut perihal Trello dan Airtable bisa dibaca pada tautan berikut:

https://developer.atlassian.com/cloud/trello/guides/rest-api/api-introduction/
https://airtable.com/api
  • Mengambil data dari Google Sheet

Google menyediakan API untuk mengambil data dari dalam google sheet melalui script misalnya menggunakan PHP. Integrasi ini bisa dimanfaatkan misal untuk meminta data pelamar, data pegawai yang belum mengisi daily report, dan lain-lain. Untuk mengambil data dari Google Sheet bisa menggunakan cara pada tautan berikut: 

https://www.srijan.net/blog/integrating-google-sheets-with-php-is-this-easy-know-how
  • Jobstreet

Untuk mengambil lowongan perusahaan bisa menggunakan curl ke

http://157.230.35.21/jobstreet_api.php

yang sudah dikonfigurasi khusus untuk mengambil lowongan di PT Akhdani Reka Solusi.

  • Build aplikasi di Jenkins

Jenkins menyediakan API untuk melakukan job pada Jenkins misalnya build aplikasi yang telah dikonfigurasi sebelumnya menggunakan REST API. Untuk informasi lebih lengkap bisa dibaca pada tautan berikut:

https://www.jenkins.io/doc/book/using/remote-access-api/

Scheduled Meeting dari Google Calendar dan Zoom

Google menyediakan API untuk membuat event meeting menggunakan Google Calendar dan generate link Google Meet secara otomatis. Seperti halnya Zoom juga menyediakan API untuk membuat meeting. Langkahnya bisa dilakukan dengan cara yang terlampir pada tautan berikut:

https://developers.google.com/calendar/create-events
https://marketplace.zoom.us/docs/api-reference/zoom-api/meetings/meetingcreate

Dalam rencana implementasi, untuk membuat event meeting menggunakan curl dengan metode seperti berikut:

https://usefulangle.com/post/29/google-calendar-api-create-event-php

 Cara Pemakaian dan Contoh

Penggunaan bot ini dilakukan melalui dua cara, yaitu jalur grup atau jalur pribadi. Dari sisi server akan ditentukan juga mana perintah yang bisa direspon hanya melalui jalur pribadi atau bisa direspon di jalur grup. Gambar di bawah ini adalah contoh implementasi bot WhatsApp untuk info lowongan pekerjaan di ARS melalui jalur pribadi dan contoh mengubah gambar menjadi stiker melalui jalur grup:

5

Gambar 5. Contoh Respon Chat Bot Melalui Pesan Pribadi

6

Gambar 6. Contoh Respon Chat Bot Melalui Pesan Grup


Masalah yang Pernah Muncul

Pada penggunaan bot ini pernah mengalami masalah, di antaranya adalah:

  • Smartphone tidak terhubung ke internet.

Disarankan handphone harus dalam keadaan selalu terhubung ke jaringan internet. Jika sewaktu-waktu jaringan internet bermasalah dan pesan tidak diterima bot, bot akan tetap membalas pesan ketika internet kembali terhubung.

  • Session web WhatsApp berakhir.

Maka harus dilakukan scan QR code ulang.

  • Error pada script/modul.

Harus ada pengecekan atau testing berkala, memastikan script selalu uptodate.

Mengenal Javascript Map dan Set

Kali ini saya akan membahas sedikit mengenai objek yang sepertinya jarang diketahui dan dipakai oleh orang-orang pada Javascript, namanya Map dan Set.

Map mirip seperti Object biasa, berfungsi untuk menyimpan collection dengan key, bedanya, key pada map ini bisa berupa tipe data yang lebih beragam, seperti primitif (angka, string, boolean), object, atau bahkan NaN.

let map = new Map();

map.set("1", "str1");
map.set(1, "num1");
map.set(true, "bool1");

let obj = {name: "Akhdani"};

map.set(obj, "obj1");
map.set(NaN, "nan1");

console.log( map.get(1)   ); // 'num1'
console.log( map.get('1') ); // 'str1'
console.log( map.get(true)); // 'bool1'
console.log( map.get(obj) ); // 'obj1'
console.log( map.get(NaN) ); // 'nan1'


console.log( map.size ); // 5

console.log( map ); // Map(5) {"1" => "str1", 1 => "num1", true => "bool1", {…} => "obj1", NaN => "nan1"}

Bisa kita lihat, Map bisa menerima apa saja sebagai keynya. Cukup ajaib menurut saya. :D

Fitur tambahannya adalah:

  • Urutan dipertahankan sesuai urutan melakukan entry.
  • Tipe data tidak diubah, sehingga key berupa string “1” dan key integer 1 tetap ada keduanya.

Bagaimana jika ingin iterasi entry Map? Ada tiga cara:

  • map.keys() untuk iterasi key
  • map.values() untuk iterasi value
  • map.entries() untuk iterasi entry, berupa key dan valuenya
for (let k of map.keys()) {
  console.log(k);
}

for (let v of map.values()) {
  console.log(v);
}

for (let entry of map) {
  console.log(entry); 
}

 

Set bisa dibilang mirip array, hanya saja tidak bisa duplikat elemen.

let set = new Set();

let akhdani = { name: "Akhdani" };
let reka = { name: "Reka" };
let solusi = { name: "Solusi" };

set.add(akhdani);
set.add(reka);
set.add(solusi);
set.add(reka);
set.add(solusi);

console.log( set.size ); // 3

for (let user of set) {
  console.log(user.name);
}

Bisa kita lihat di atas meskipun “reka” dan “solusi” di-add dua kali, set tetap hanya berisi 3 elemen. Urutan tentu saja dipertahankan karena lebih mirip seperti array.

Template Literal pada Javascript

Kali ini saya ada bahasan sedikit mengenai template literal, masih dari fitur Javascript yang ditambahkan sejak EcmaScript 6.

Salah satu yang sering kita lakukan saat membuat aplikasi adalah menggabungkan string dengan hasil ekspresi, misalnya untuk menampilkan pesan error atau informasi. Misalnya menulis halaman “Selamat datang, Akdani”, di mana kata “Akhdani” diambil dari data pengguna yang login ke aplikasi. Pada javascript ES5, kita menulisnya seperti ini:

var nama = “Akhdani”;

var pesan = “Selamat datang, " + nama + “!”;

console.log(pesan); // “Selamat datang, Akhdani!”

Nah, sekarang kita bisa menggunakan template literal ini sehingga kita bisa mengurangi penggunaan simbol operator tambah. Kita bisa menulis kalimat yang sama tanpa menggunakan simbol operator tambah, hanya saja kita harus menggunakan backtick (`), lokasi tombolnya pada keyboard ada di sebelah kiri angka 1. Contohnya:

var nama = “Akhdani”;

var pesan = `Selamat datang, ${nama}!`;

console.log(pesan); // “Selamat datang, Akhdani!”

Untuk string dengan banyak baris, kita bisa langsung menuliskan string pada kode dalam bentuk banyak baris tanpa menggunakan ‘\n’, tapi tetap menggunakan backtick. Contoh:

console.log(`Nama saya Akhdani

saya bekerja di Akhdani Reka Solusi`);

// “Nama saya Akhdani

// saya bekerja di Akhdani Reka Solusi”

Untuk bentuk yang lebih lanjut, ada tagged template. Dengan tag ini bisa mengolah template literal menggunakan fungsi. Contoh:

function myTag(strings, nama, umur){
    var str1 = strings[0];

    var str2 = strings[1];

    var str3 = strings[2];

    return `${str1}${nama}${str2}${umur}${str3}`;
};

var nama = “Akhdani”;

var umur = 28;

var hasil = myTag`Halo, nama saya ${nama}, umur saya ${umur} tahun.`;

console.log(hasil); // “Halo, nama saya Akhdani, umur saya 28 tahun.”;

Untuk tag di atas, kalau masih bingung bagaimana pemetaan dari string yang diberi tag ke dalam argumen fungsi tagnya, begini caranya:

  1. String selain hasil interpolasi akan masuk sebagai argumen pertama dalam bentuk array, untuk contoh di atas, terdiri dari 3, yaitu:
    • “Halo, nama saya “;
    • “, umur saya “;
    • ” tahun.”
  2. Ekspresi interpolasi (${nama} dan ${umur}) akan masuk sebagai argumen sisanya yang terpisah, tidak dalam satu array;

Oh ya ketinggalan, kalau ingin ada backtick di dalam template ini, bisa di-escape dengan backslash..

`\`` === '`' // --> true

Sepertinya fitur ini akan sangat berguna apabila aplikasi kita banyak menuliskan string yang terdapat bagian yang merupakan hasil ekspresi kode program. Setidaknya yang akan sering dipakai adalah sintak dasar.

Sekian saja postingan pendek kali ini. semoga bermanfaat. :)

Berkenalan Dengan Javascript Arrow Function

Kali ini kita akan mengenal salah satu fitur Javascript yang ditambahkan sejak EcmaScript 6, yaitu arrow function.

Arrow function adalah sintak penulisan fungsi yang bisa dibilang lebih singkat, menggunakan token baru yaitu “=>”, fungsi yang dideklarasikan menggunakan panah ini bersifat anonim. Mirip lambda arrow operator di bahasa lain. Dengan arrow function kita bisa menulis fungsi tanpa menggunakan kata kunci “function”, “return”, dan kurung kurawal. Oke mari kita langsung saja membahas sedikit.

Sintak banyak parameter:

// ES5
var multiplyES5 = function(x, y) {
  return x * y;
};

// ES6
var multiplyES6 = (x, y) => { return x * y };

console.log(multiplyES6 (2,3));  // 6

Berhubung contoh fungsi multiplyES6 di atas hanya satu ekspresi, maka bisa disingkat lagi:

var multiplyES6 = (x, y) => x * y;

console.log(multiplyES6 (2,3));  // 6

 

Sintak satu parameter:

Jika parameter hanya satu, tidak wajib menggunakan tanda kurung.

//ES5
var phraseSplitterEs5 = function phraseSplitter(phrase) {
  return phrase.split(' ');
};

//ES6

var phraseSplitterEs6 = phrase => phrase.split(" ");

console.log(phraseSplitterEs6("ES6 Awesomeness"));  // ["ES6", "Awesomeness"]

 

Sintak tanpa parameter:

//ES5
var docLogEs5 = function docLog() {
    console.log(document);
};

//ES6
var docLogEs6 = () => { console.log(document); };

docLogEs6(); // #document... <html> ….

 

Sintak returnnya object:

Jika return object, maka harus dibungkus tanda kurung agar bias membedakan antara blok fungsi dengan objek.

//ES5
var setNameIdsEs5 = function setNameIds(id, name) {
  return {
    id: id,
    name: name
  };
};

// ES6
var setNameIdsEs6 = (id, name) => ({ id: id, name: name });

console.log(setNameIdsEs6 (1, "Akhdani"));   // Object {id: 1, name: "Akhdani"}

 

Apakah ada batasan pada arrow function ini?

  1. Arrow function paling baik digunakan untuk fungsi non-method. Perhatikan contoh berikut:
'use strict';
var obj = {
  i: 10,
  b: () => console.log(this.i, this),
  c: function() {
    console.log(this.i, this);
  }
}

obj.b(); // prints undefined, Window {...} (or the global object)
obj.c(); // prints 10, Object {...}

Dari contoh di atas bisa dilihat fungsi b() tidak bisa mengakses properti i, saat mengakses this, ia justru menghasilkan global object.

  1. Arrow function tidak bisa digunakan sebagai konstruktor dan akan terjadi error jika menggunakan new.
var Foo = () => {};
var foo = new Foo(); // TypeError: Foo is not a constructor
  1. Arrow function tidak memiliki objek arguments.
var f = () => arguments[0] + n;
f(2); // Uncaught ReferenceError: arguments is not defined

Arrow function ini bisa digunakan pada javascript higher order function pada postingan saya sebelumnya, silakan coba-coba. :D

Mungkin untuk sementara sekian dulu saja, jika ada tambahan, maka akan saya tambahkan di kemudian hari.

Terima kasih. :)

Berkenalan dengan Javascript Higher Order Function untuk Array

Halo! Salam, perkenalkan saya Aria, saya adalah salah satu dari tim kontributor baru di blog Akhdani ini, saya tidak ada spesialisasi teknologi, jadi apa ilmu yang saya punya akan saya tuangkan di blog ini.

Untuk postingan pertama di sini, saya akan membahas higher-order function untuk array pada Javascript. Beberapa fungsi ada yang sepertinya sudah sering dipakai, tapi saya akan tetap sedikit membahas untuk semuanya. Fungsi-fungsi ini sebenarnya cenderung functional programming, tapi kita abaikan dulu saja. Nah, apa fungsinya? Salah satunya agar kode program kita sedikit lebih “bersih”, operasi pada array tidak perlu lagi menggunakan looping semacam for atau while.

(Mohon maaf sebelumnya jika ada penjelasan yang masih sulit dipahami, saya berusaha menjelaskan semudah mungkin. Silakan komentari artikel ini jika ada pertanyaan)

Sebelum mulai, diketahui kita memiliki array yang akan melakukan fungsi-fungsi higher-order ini.

var source = [1,2,3,4,5];
  1. forEach

Looping pada semua elemen array, dan menjalankan operasi yang kita berikan.

Contoh:

source.forEach(function(currentValue, currentIndex){
   console.log("index", currentIndex, "isinya", currentValue);
});

// index 0 isinya 1
// index 1 isinya 2
// index 2 isinya 3
// index 3 isinya 4
// index 4 isinya 5

 

  1. filter

Looping pada semua elemen array, setiap elemen yang memenuhi kondisi akan dimasukkan ke dalam array hasil fungsi filter, array sumber akan tetap utuh.

Contoh:

var filterGanjil = source.filter(function(currentValue, currentIndex){
   return currentValue % 2 === 1;
});

console.log(filterGanjil); // [1, 3, 5]

 

  1. map

Looping pada semua elemen array, dan menjalankan operasi pada masing-masing elemen array. Hasilnya adalah array dengan panjang (length) yang sama namun isinya berupa hasil dari operasi pada masing-masing elemen array yang bersesuaian.

Contoh:

var dikaliDua = source.map(function(currentValue, currentIndex){
   return currentValue * 2;
});

console.log(dikaliDua); // [2, 4, 6, 8, 10]

 

  1. reduce

Looping pada semua elemen array, dan menjalankan operasi pada elemen array. Hasil operasi pada elemen ke-i, akan dijadikan parameter untuk operasi pada elemen berikutnya (i+1), sehingga hasil operasi reduce adalah akumulasi operasi pada semua elemen, bukan array. Pendeknya, value yang tadinya banyak (array) menjadi satu saja.

Contoh:

var ditotalin = source.reduce(function(previousValue, currentValue, currentIndex){
   return previousValue + currentValue;
});

console.log(ditotalin); // 15

Untuk reduce, bisa ditambahkan parameter kedua yaitu initial value sebagai nilai permulaan sebelum reduce dieksekusi. Jadi seb

Contoh:

var ditotalin = source.reduce(function(previousValue, currentValue, currentIndex){
   return previousValue + currentValue;
}, 5);

console.log(ditotalin); // 20
  1. reduceRight

Sama seperti reduce, hanya saja dilakukan mulai dari elemen terakhir.

Contoh:

var ditotalinDariKanan = source.reduceRight(function(previousValue, currentValue, currentIndex){
   return previousValue + currentValue;
});

console.log(ditotalinDariKanan); // 15

Sama seperti reduce, reduceRight juga bisa ditambahkan parameter kedua sebagai initial value.

 

  1. some

Looping pada setiap elemen array dan menjalankan operasi pada setiap elemen array, jika ada satu saja yang hasilnya true, maka hasil fungsi some adalah true.

Contoh:

var apakahAdaAngkaTiga = source.some(function(currentValue, currentIndex){
   return currentValue === 3;
});

console.log(apakahAdaAngkaTiga); // true
  1. every

Mirip seperti some namun hasil operasi semua elemen harus bernilai true agar hasil fungsi every adalah true.

Contoh:

var apakahSemuanyaAngka = source.every(function(currentValue, currentIndex){
   return typeof currentValue === "number";
});

console.log(apakahSemuanyaAngka); //true
  1. find

Menampilkan isi elemen pertama yang memenuhi kondisi yang ditentukan, jika tidak ada maka hasilnya adalah undefined.

Contoh:

var angkaYangLebihBesarDariDua = source.find(function(currentValue, currentIndex){
   return currentValue > 2;
});
console.log(angkaYangLebihBesarDariDua); // 3
  1. findIndex

Menampilkan index elemen pertama yang memenuhi kondisi yang ditentukan, jika tidak ada maka hasilnya adalah -1.

Contoh:

var indexnyaAngkaYangLebihBesarDariDua = source.findIndex(function(currentValue, currentIndex){
   return currentValue > 2;
});

console.log(indexnyaAngkaYangLebihBesarDariDua); // 2

Nah, bagaimana kalau mau digabung? Contohnya, setelah difilter, ingin dilakukan map. Caranya adalah dengan method/function chaining, caranya seperti ini:

 var filterGanjilLaluKaliDua = source
   .filter(function(currentValue, currentIndex){
      return currentValue % 2 === 1;
   })
   .map(function(currentValue, currentIndex){
      return currentValue * 2;
   });

console.log(filterGanjilLaluKaliDua); // [2, 6, 10]

Tapi ingat, chaining di atas bisa dilakukan karena hasil dari filter adalah array, jadi masih memiliki method map. Kalau awalnya, misalnya, di­-reduce, hasilnya bukanlah array sehingga tidak memiliki method map.

Sekian saja bahasan sedikit dari saya, jika ada kesempatan maka akan saya bahas lebih dalam, jika ada pertanyaan silakan tulis komentar. Semoga bermanfaat!

Salam…