Ayogiakbar

CEK RESI + ONGKIR

Oct 2nd, 2025
55
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. // AUTHOR GIENETIC + FIX NORMALIZER
  2.  
  3. const axios = require("axios");
  4. const qs = require("qs");
  5.  
  6. const BASE_URL_RESI = "https://loman.id/resapp/";
  7. const BASE_URL_ONGKIR = "https://loeman.loman.id/";
  8. const HEADER_DEFAULT = {
  9.   "user-agent": "Dart/3.6 (dart:io)",
  10.   "accept-encoding": "gzip",
  11. };
  12.  
  13. /**
  14.  * Cek status pengiriman berdasarkan nomor resi dan ekspedisi.
  15.  * Hasil selalu dinormalisasi agar seragam.
  16.  */
  17. async function cekResi(resi, ekspedisi) {
  18.   try {
  19.     const payload = qs.stringify({ resi, ex: ekspedisi });
  20.     const response = await axios.post(BASE_URL_RESI, payload, {
  21.       headers: {
  22.         ...HEADER_DEFAULT,
  23.         "content-type": "application/x-www-form-urlencoded; charset=utf-8",
  24.       },
  25.     });
  26.  
  27.     const raw = response.data;
  28.  
  29.     if (raw.status !== "berhasil") {
  30.       return {
  31.         status: "gagal",
  32.         message: raw.message || raw.details || "Resi tidak ditemukan",
  33.       };
  34.     }
  35.  
  36.     // Normalisasi ke format konsisten
  37.     const details = raw.details || raw.infopengiriman || {};
  38.     const history = raw.history || raw.tracking || [];
  39.  
  40.     return {
  41.       status: "berhasil",
  42.       details: {
  43.         status: details.status || raw.status || "-",
  44.         infopengiriman:
  45.           details.infopengiriman ||
  46.           raw.infopengiriman ||
  47.           "Tidak ada info pengiriman",
  48.         ucapan:
  49.           details.ucapan ||
  50.           raw.ucapan ||
  51.           "Selamat paket berhasil dilacak",
  52.       },
  53.       history: history.map((h) => ({
  54.         tanggal: h.tanggal || h.date || "-",
  55.         details: h.details || h.desc || h.keterangan || "-",
  56.       })),
  57.     };
  58.   } catch (error) {
  59.     return {
  60.       status: "gagal",
  61.       message: error.message,
  62.     };
  63.   }
  64. }
  65.  
  66. /**
  67.  * Cek ongkos kirim antar lokasi (kab/kota/kecamatan).
  68.  */
  69. async function cekOngkir(asal, tujuan, berat) {
  70.   try {
  71.     const asalResult = await cariIdKotaDenganSaran(asal);
  72.     const tujuanResult = await cariIdKotaDenganSaran(tujuan);
  73.  
  74.     if (!asalResult.id || !tujuanResult.id) {
  75.       let pesan = `Lokasi `;
  76.       if (!asalResult.id) pesan += `asal \"${asal}\" tidak ditemukan.`;
  77.      if (!tujuanResult.id)
  78.        pesan += `${!asalResult.id ? "\n" : ""}tujuan \"${tujuan}\" tidak ditemukan.`;
  79.  
  80.      const saran = [];
  81.      if (asalResult.saran.length)
  82.        saran.push(
  83.          `🔍 Mungkin maksud asal:\n- ${asalResult.saran.map((x) => x.nama).join("\n- ")}`,
  84.        );
  85.      if (tujuanResult.saran.length)
  86.        saran.push(
  87.          `🔍 Mungkin maksud tujuan:\n- ${tujuanResult.saran.map((x) => x.nama).join("\n- ")}`,
  88.        );
  89.  
  90.      return {
  91.        status: "gagal",
  92.        message: `${pesan}${saran.length ? "\n\n" + saran.join("\n\n") : ""}`,
  93.      };
  94.    }
  95.  
  96.    const payload = {
  97.      idAsal: asalResult.id,
  98.      idTujuan: tujuanResult.id,
  99.      berat: String(berat),
  100.    };
  101.  
  102.    const response = await axios.post(BASE_URL_ONGKIR, payload, {
  103.      headers: {
  104.        ...HEADER_DEFAULT,
  105.        "content-type": "application/json; charset=utf-8",
  106.      },
  107.    });
  108.  
  109.    return {
  110.      ...response.data,
  111.      detail: {
  112.        dari: asalResult.nama,
  113.        menuju: tujuanResult.nama,
  114.        berat: berat + " kg",
  115.      },
  116.    };
  117.  } catch (error) {
  118.    return {
  119.      status: "gagal",
  120.      message: error.message,
  121.    };
  122.  }
  123. }
  124.  
  125. /**
  126. * Ambil daftar ekspedisi dari API.
  127. */
  128. async function cekEkspedisi() {
  129.  try {
  130.    const res = await axios.get(BASE_URL_RESI + "getdropdown.php", {
  131.      headers: HEADER_DEFAULT,
  132.    });
  133.  
  134.    return res.data.status === "berhasil"
  135.      ? res.data.data.map((item) => item.title)
  136.      : [];
  137.  } catch (error) {
  138.    return [];
  139.  }
  140. }
  141.  
  142. /**
  143. * Cari daftar lokasi berdasarkan keyword (bisa kota/kecamatan/kabupaten).
  144. */
  145. async function cariKota(keyword) {
  146.  try {
  147.    const url = `${BASE_URL_ONGKIR}?cari=${encodeURIComponent(keyword)}`;
  148.    const response = await axios.get(url, { headers: HEADER_DEFAULT });
  149.    return Array.isArray(response.data) ? response.data : [];
  150.  } catch (error) {
  151.    return [];
  152.  }
  153. }
  154.  
  155. /**
  156. * Ambil ID lokasi dan saran berdasarkan nama lokasi.
  157. */
  158. async function cariIdKotaDenganSaran(namaKota) {
  159.  const keywords = namaKota.toLowerCase().split(/\s+/).filter(Boolean);
  160.  const candidates = await Promise.all(keywords.map((k) => cariKota(k)));
  161.  
  162.  const semua = Object.values(
  163.    [].concat(...candidates).reduce((acc, item) => {
  164.      acc[item.id] = item;
  165.      return acc;
  166.    }, {}),
  167.  );
  168.  
  169.  const cocok = semua.find((item) => {
  170.    const name = item.nama.toLowerCase();
  171.    return keywords.every((k) => name.includes(k));
  172.  });
  173.  
  174.  return {
  175.    id: cocok ? cocok.id : null,
  176.    nama: cocok ? cocok.nama : namaKota,
  177.    saran: cocok ? [] : semua.slice(0, 5),
  178.  };
  179. }
  180.  
  181. module.exports = {
  182.  cekResi,
  183.  cekOngkir,
  184.  cekEkspedisi,
  185. };
  186.  
Advertisement
Add Comment
Please, Sign In to add comment