Case v1 - Javascript

by PayKu

16
Raw
case 'qris2': {
  const CONFIG = {
    apiKey: 'PAYKU_1234567890', // Apikey
    secretKey: '11111aaaaa22222bbbbb33333ccccc44444dddddd55555eeeee',
    baseURL: 'https://payku.my.id',
    minAmount: 1000, // minimal deposit
    maxChecks: 10, 
    checkInterval: 5000
  };

  if (!global.activeTransactions) {
    global.activeTransactions = new Map();
  }

  const generateSignature = (data, secretKey) => {
    const sortedKeys = Object.keys(data).sort();
    const stringToSign = sortedKeys.map(k => `${k}=${data[k]}`).join('&');
    return crypto.createHmac('sha256', secretKey).update(stringToSign).digest('hex');
  };

  const createHeaders = (data, timestamp) => {
    const signature = generateSignature(data, CONFIG.secretKey);
    return {
      'x-api-key': CONFIG.apiKey,
      'x-signature': signature,
      'x-timestamp': timestamp,
      'Content-Type': 'application/json'
    };
  };

  const sanitizeUserId = (userId) => userId.replace(/[^0-9]/g, '');
  const createTransaction = async (nominal, userId, pushname) => {
    const timestamp = Date.now().toString();
    const sanitizedUserId = sanitizeUserId(userId);
    const transactionData = {
      external_id: `BOT-${sanitizedUserId}`,
      amount: nominal,
      description: `Top Up QRIS Rp${nominal.toLocaleString()}`,
      customer_name: pushname || userId.split('@')[0],
      customer_email: `${sanitizedUserId}@gmail.com`,
      customer_phone: sanitizedUserId,
      timestamp
    };

    const headers = createHeaders(transactionData, timestamp);

    try {
      const response = await axios.post(`${CONFIG.baseURL}/api/create-transaction`, transactionData, { headers });
      
      if (!response.data.success) {
        throw new Error(response.data.message || 'Gagal membuat transaksi');
      }
      
      return response.data.data;
    } catch (error) {
      throw new Error(`API Error: ${error.response?.data?.message || error.message}`);
    }
  };

  const checkTransactionStatus = async (transactionId) => {
    const timestamp = Date.now().toString();
    const data = { transaction_id: transactionId, timestamp };
    const headers = createHeaders(data, timestamp);

    try {
      const response = await axios.get(`${CONFIG.baseURL}/api/transaction/${transactionId}`, { headers });
      
      if (!response.data.success) {
        throw new Error(response.data.message || 'Gagal mengecek status transaksi');
      }
      
      return response.data.data;
    } catch (error) {
      throw new Error(`API Error: ${error.response?.data?.message || error.message}`);
    }
  };

  const cancelTransaction = async (transactionId) => {
    const timestamp = Date.now().toString();
    const data = { transaction_id: transactionId, timestamp };
    const headers = createHeaders(data, timestamp);

    try {
      const response = await axios.post(`${CONFIG.baseURL}/api/transaction/${transactionId}/cancel`, {}, { headers });
      
      if (!response.data.success) {
        throw new Error(response.data.message || 'Gagal membatalkan transaksi');
      }
      
      return response.data.message;
    } catch (error) {
      throw new Error(`API Error: ${error.response?.data?.message || error.message}`);
    }
  };

  const formatQRISMessage = (transaction) => {
    return `✅ *QRIS Siap Digunakan*

• ID: ${transaction.transaction_id}
• Nominal: Rp${transaction.amount.toLocaleString()}
• Fee: Rp${transaction.fee.toLocaleString()}
• Total Bayar: Rp${transaction.total_amount.toLocaleString()}

📥 Klik untuk bayar via QRIS
🔗 ${transaction.qris_url}

_Selama belum dibayar, bot akan cek otomatis..._
_Ketik "cancel" untuk membatalkan pembayaran._`;
  };

  const formatSuccessMessage = (statusData) => {
    return `✅ *Pembayaran Berhasil!*

• Nominal yang akan ditambahkan: Rp${statusData.amount.toLocaleString()}
• Total Dibayar: Rp${statusData.total_amount.toLocaleString()}
• Metode: ${statusData.payment_method}
• Dibayar: ${statusData.paid_at}

*Catatan:* Fee adalah pajak layanan dan tidak ditambahkan ke saldo Anda.`;
  };

  const pollPaymentStatus = async (transactionId, userId) => {
    let status = 'pending';
    let checkCount = 0;

    while (status === 'pending' && checkCount < CONFIG.maxChecks) {
      await new Promise(resolve => setTimeout(resolve, CONFIG.checkInterval));
      
      if (!global.activeTransactions.has(userId)) {
        console.log(`Transaction ${transactionId} was cancelled by user`);
        return false;
      }
      
      try {
        const statusData = await checkTransactionStatus(transactionId);
        status = statusData.status;
        checkCount++;

        if (status === 'paid') {
          global.activeTransactions.delete(userId);
          
          await Ditss.sendMessage(m.chat, {
            text: formatSuccessMessage(statusData)
          }, { quoted: m });
          return true;
        }
      } catch (error) {
        console.error(`Error checking status (attempt ${checkCount + 1}):`, error);
        checkCount++;
      }
    }

    if (status !== 'paid' && global.activeTransactions.has(userId)) {
      global.activeTransactions.delete(userId);
      
      await Ditss.sendMessage(m.chat, {
        text: `⚠️ Pembayaran belum diterima setelah ${CONFIG.maxChecks} kali pengecekan. QRIS telah expired.`
      }, { quoted: m });
    }

    return false;
  };

  if (!text) return m.reply('❌ Format salah!\n\nContoh:\n• .qris2 15000\n• Ketik "cancel" untuk membatalkan');

  if (text.toLowerCase() === 'cancel') {
    const userId = m.sender;
    const activeTransaction = global.activeTransactions.get(userId);
    
    if (!activeTransaction) {
      return m.reply('❌ Tidak ada transaksi QRIS yang sedang aktif untuk dibatalkan.');
    }

    try {
      const message = await cancelTransaction(activeTransaction.transactionId);
      global.activeTransactions.delete(userId);
      
      m.reply(`✅ Transaksi berhasil dibatalkan dan QR QRIS telah dihapus!\n\n${message}`);
    } catch (error) {
      console.error('Cancel transaction error:', error);
      global.activeTransactions.delete(userId);
      m.reply(`⚠️ QR QRIS telah dihapus. ${error.message}`);
    }
    break;
  }

  if (text.startsWith('cancel ')) {
    const transactionId = text.split(' ')[1];
    if (!transactionId) {
      return m.reply('❌ Masukkan ID transaksi yang ingin dibatalkan.\nContoh: .qris2 cancel TRX123456');
    }

    try {
      const message = await cancelTransaction(transactionId);
      global.activeTransactions.delete(m.sender);
      
      m.reply(`✅ ${message}`);
    } catch (error) {
      console.error('Cancel transaction error:', error);
      m.reply(`❌ Gagal membatalkan transaksi: ${error.message}`);
    }
    break;
  }

  const nominal = parseInt(text);
  if (isNaN(nominal) || nominal < CONFIG.minAmount) {
    return m.reply(`❌ Masukkan nominal minimal Rp${CONFIG.minAmount.toLocaleString()}\nContoh: .qris2 15000`);
  }

  if (global.activeTransactions.has(m.sender)) {
    const activeTransaction = global.activeTransactions.get(m.sender);
    return m.reply(`❌ Anda masih memiliki transaksi QRIS yang aktif!\n\nID: ${activeTransaction.transactionId}\nNominal: Rp${activeTransaction.amount.toLocaleString()}\n\nKetik "cancel" untuk membatalkan transaksi sebelumnya, atau tunggu hingga selesai.`);
  }

  try {
    const transaction = await createTransaction(nominal, m.sender, pushname);
    global.activeTransactions.set(m.sender, {
      transactionId: transaction.transaction_id,
      amount: transaction.amount,
      createdAt: Date.now()
    });

    await Ditss.sendMessage(m.chat, {
      image: { url: transaction.qris_url },
      caption: formatQRISMessage(transaction)
    }, { quoted: m });

    pollPaymentStatus(transaction.transaction_id, m.sender).catch(error => {
      console.error('Polling payment status error:', error);
      global.activeTransactions.delete(m.sender);
    });

  } catch (error) {
    console.error('Create transaction error:', error);
    m.reply(`❌ Gagal membuat transaksi: ${error.message}`);
  }
}
break;