implement menu debit dan qris
This commit is contained in:
parent
459d9ab0f1
commit
2a24016637
@ -33,7 +33,6 @@
|
||||
<activity
|
||||
android:name=".PaymentActivity"
|
||||
android:exported="false" />
|
||||
<activity android:name=".QrisResultActivity" />
|
||||
<activity
|
||||
android:name=".PinActivity"
|
||||
android:screenOrientation="portrait"
|
||||
@ -42,6 +41,10 @@
|
||||
<activity
|
||||
android:name=".ReceiptActivity"
|
||||
android:exported="false" />
|
||||
<activity
|
||||
android:name=".QrisActivity"
|
||||
android:exported="false" />
|
||||
<activity android:name=".QrisResultActivity" />
|
||||
</application>
|
||||
|
||||
</manifest>
|
@ -86,11 +86,11 @@ public class MainActivity extends AppCompatActivity {
|
||||
if (cardId == R.id.card_kartu_kredit) {
|
||||
startActivity(new Intent(MainActivity.this, PaymentActivity.class));
|
||||
} else if (cardId == R.id.card_kartu_debit) {
|
||||
Toast.makeText(this, "Kartu Debit Diklik", Toast.LENGTH_SHORT).show();
|
||||
startActivity(new Intent(MainActivity.this, PaymentActivity.class));
|
||||
} else if (cardId == R.id.card_qris) {
|
||||
startActivity(new Intent(MainActivity.this, TransactionActivity.class));
|
||||
startActivity(new Intent(MainActivity.this, QrisActivity.class));
|
||||
} else if (cardId == R.id.card_bantuan) {
|
||||
Toast.makeText(this, "Bantuan Diklik", Toast.LENGTH_SHORT).show();
|
||||
startActivity(new Intent(MainActivity.this, TransactionActivity.class));
|
||||
} else if (cardId == R.id.card_info_toko) {
|
||||
Toast.makeText(this, "Info Toko Diklik", Toast.LENGTH_SHORT).show();
|
||||
} else {
|
||||
|
557
app/src/main/java/com/example/bdkipoc/QrisActivity.java
Normal file
557
app/src/main/java/com/example/bdkipoc/QrisActivity.java
Normal file
@ -0,0 +1,557 @@
|
||||
package com.example.bdkipoc;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.graphics.Bitmap;
|
||||
import android.os.AsyncTask;
|
||||
import android.os.Bundle;
|
||||
import android.util.Log;
|
||||
import android.view.MenuItem;
|
||||
import android.view.View;
|
||||
import android.view.inputmethod.InputMethodManager;
|
||||
import android.widget.Button;
|
||||
import android.widget.EditText;
|
||||
import android.widget.ImageView;
|
||||
import android.widget.ProgressBar;
|
||||
import android.widget.TextView;
|
||||
import android.widget.Toast;
|
||||
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.appcompat.app.AppCompatActivity;
|
||||
import androidx.appcompat.widget.Toolbar;
|
||||
|
||||
import org.json.JSONException;
|
||||
import org.json.JSONObject;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.InputStreamReader;
|
||||
import java.io.OutputStream;
|
||||
import java.net.HttpURLConnection;
|
||||
import java.net.URI;
|
||||
import java.net.URISyntaxException;
|
||||
import java.net.URL;
|
||||
import java.util.Random;
|
||||
import java.util.UUID;
|
||||
|
||||
public class QrisActivity extends AppCompatActivity {
|
||||
|
||||
private ProgressBar progressBar;
|
||||
private Button initiatePaymentButton;
|
||||
private Button simulatePaymentButton;
|
||||
private ImageView qrCodeImageView;
|
||||
private TextView statusTextView;
|
||||
private EditText editTextAmount;
|
||||
private TextView referenceIdTextView;
|
||||
private View paymentDetailsLayout;
|
||||
private View paymentSuccessLayout;
|
||||
private Button returnToMainButton;
|
||||
|
||||
private String transactionId;
|
||||
private String transactionUuid;
|
||||
private String referenceId;
|
||||
private int amount;
|
||||
private JSONObject midtransResponse;
|
||||
|
||||
private static final String BACKEND_BASE = "https://be-edc.msvc.app";
|
||||
private static final String MIDTRANS_CHARGE_URL = "https://api.sandbox.midtrans.com/v2/charge";
|
||||
private static final String MIDTRANS_AUTH = "Basic U0ItTWlkLXNlcnZlci1JM2RJWXdIRzVuamVMeHJCMVZ5endWMUM="; // Replace with your actual key
|
||||
private static final String WEBHOOK_URL = "https://be-edc.msvc.app/webhooks/midtrans";
|
||||
|
||||
@Override
|
||||
protected void onCreate(@Nullable Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
setContentView(R.layout.activity_qris);
|
||||
|
||||
// Set up the toolbar
|
||||
Toolbar toolbar = findViewById(R.id.toolbar);
|
||||
setSupportActionBar(toolbar);
|
||||
if (getSupportActionBar() != null) {
|
||||
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
|
||||
getSupportActionBar().setDisplayShowHomeEnabled(true);
|
||||
getSupportActionBar().setTitle("QRIS Payment");
|
||||
}
|
||||
|
||||
// Initialize views
|
||||
progressBar = findViewById(R.id.progressBar);
|
||||
initiatePaymentButton = findViewById(R.id.initiatePaymentButton);
|
||||
simulatePaymentButton = findViewById(R.id.simulatePaymentButton);
|
||||
qrCodeImageView = findViewById(R.id.qrCodeImageView);
|
||||
statusTextView = findViewById(R.id.statusTextView);
|
||||
editTextAmount = findViewById(R.id.editTextAmount);
|
||||
referenceIdTextView = findViewById(R.id.referenceIdTextView);
|
||||
paymentDetailsLayout = findViewById(R.id.paymentDetailsLayout);
|
||||
paymentSuccessLayout = findViewById(R.id.paymentSuccessLayout);
|
||||
returnToMainButton = findViewById(R.id.returnToMainButton);
|
||||
|
||||
// Generate a random amount between 100,000 and 999,999
|
||||
amount = new Random().nextInt(900000) + 100000;
|
||||
|
||||
// Format and display the amount
|
||||
editTextAmount.setText("");
|
||||
editTextAmount.requestFocus();
|
||||
InputMethodManager imm = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE);
|
||||
if (imm != null) {
|
||||
imm.showSoftInput(editTextAmount, InputMethodManager.SHOW_IMPLICIT);
|
||||
}
|
||||
|
||||
// Generate reference ID
|
||||
referenceId = "ref-" + generateRandomString(8);
|
||||
referenceIdTextView.setText(referenceId);
|
||||
|
||||
// Set up click listeners
|
||||
initiatePaymentButton.setOnClickListener(v -> createTransaction());
|
||||
simulatePaymentButton.setOnClickListener(v -> simulateWebhook());
|
||||
returnToMainButton.setOnClickListener(v -> finish());
|
||||
|
||||
// Initially hide the QR code and payment success views
|
||||
paymentDetailsLayout.setVisibility(View.GONE);
|
||||
paymentSuccessLayout.setVisibility(View.GONE);
|
||||
simulatePaymentButton.setVisibility(View.GONE);
|
||||
}
|
||||
|
||||
private void createTransaction() {
|
||||
progressBar.setVisibility(View.VISIBLE);
|
||||
initiatePaymentButton.setEnabled(false);
|
||||
statusTextView.setText("Creating transaction...");
|
||||
|
||||
new CreateTransactionTask().execute();
|
||||
}
|
||||
|
||||
private void displayQrCode(String qrImageUrl) {
|
||||
new DownloadImageTask().execute(qrImageUrl);
|
||||
}
|
||||
|
||||
private void simulateWebhook() {
|
||||
progressBar.setVisibility(View.VISIBLE);
|
||||
simulatePaymentButton.setEnabled(false);
|
||||
statusTextView.setText("Processing payment...");
|
||||
|
||||
new SimulateWebhookTask().execute();
|
||||
}
|
||||
|
||||
private void showSuccessScreen() {
|
||||
paymentDetailsLayout.setVisibility(View.GONE);
|
||||
paymentSuccessLayout.setVisibility(View.VISIBLE);
|
||||
statusTextView.setText("Payment successful!");
|
||||
progressBar.setVisibility(View.GONE);
|
||||
}
|
||||
|
||||
private String generateRandomString(int length) {
|
||||
String chars = "abcdefghijklmnopqrstuvwxyz0123456789";
|
||||
StringBuilder sb = new StringBuilder();
|
||||
Random random = new Random();
|
||||
for (int i = 0; i < length; i++) {
|
||||
int index = random.nextInt(chars.length());
|
||||
sb.append(chars.charAt(index));
|
||||
}
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
private String getServerKey() {
|
||||
// MIDTRANS_AUTH = 'Basic base64string'
|
||||
String base64 = MIDTRANS_AUTH.replace("Basic ", "");
|
||||
String decoded = android.util.Base64.decode(base64, android.util.Base64.DEFAULT).toString();
|
||||
// Format is usually 'SB-Mid-server-xxxx:'. Remove trailing colon if present.
|
||||
return decoded.replace(":\n", "");
|
||||
}
|
||||
|
||||
private String generateSignature(String orderId, String statusCode, String grossAmount, String serverKey) {
|
||||
String input = orderId + statusCode + grossAmount + serverKey;
|
||||
try {
|
||||
java.security.MessageDigest md = java.security.MessageDigest.getInstance("SHA-512");
|
||||
byte[] messageDigest = md.digest(input.getBytes());
|
||||
StringBuilder hexString = new StringBuilder();
|
||||
for (byte b : messageDigest) {
|
||||
String hex = Integer.toHexString(0xff & b);
|
||||
if (hex.length() == 1) hexString.append('0');
|
||||
hexString.append(hex);
|
||||
}
|
||||
return hexString.toString();
|
||||
} catch (java.security.NoSuchAlgorithmException e) {
|
||||
return "";
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onOptionsItemSelected(MenuItem item) {
|
||||
if (item.getItemId() == android.R.id.home) {
|
||||
finish();
|
||||
return true;
|
||||
}
|
||||
return super.onOptionsItemSelected(item);
|
||||
}
|
||||
|
||||
private class CreateTransactionTask extends AsyncTask<Void, Void, Boolean> {
|
||||
private String errorMessage;
|
||||
|
||||
@Override
|
||||
protected Boolean doInBackground(Void... voids) {
|
||||
try {
|
||||
// Generate a UUID for the transaction
|
||||
transactionUuid = UUID.randomUUID().toString();
|
||||
|
||||
// Create transaction JSON payload
|
||||
JSONObject payload = new JSONObject();
|
||||
payload.put("type", "PAYMENT");
|
||||
payload.put("channel_category", "RETAIL_OUTLET");
|
||||
payload.put("channel_code", "QRIS");
|
||||
payload.put("reference_id", referenceId);
|
||||
|
||||
// Read amount from EditText and log it
|
||||
String amountText = editTextAmount.getText().toString().trim();
|
||||
Log.d("MidtransCharge", "Raw amount text: " + amountText);
|
||||
|
||||
try {
|
||||
// Parse amount - expecting integer in lowest denomination (Indonesian Rupiah)
|
||||
amount = Integer.parseInt(amountText);
|
||||
Log.d("MidtransCharge", "Parsed amount: " + amount);
|
||||
} catch (NumberFormatException e) {
|
||||
Log.e("MidtransCharge", "Amount parsing error: " + e.getMessage());
|
||||
errorMessage = "Invalid amount format";
|
||||
return false;
|
||||
}
|
||||
|
||||
payload.put("amount", amount);
|
||||
payload.put("cashflow", "MONEY_IN");
|
||||
payload.put("status", "INIT");
|
||||
payload.put("device_id", 1);
|
||||
payload.put("transaction_uuid", transactionUuid);
|
||||
payload.put("transaction_time_seconds", 0.0);
|
||||
payload.put("device_code", "PB4K252T00021");
|
||||
payload.put("merchant_name", "Marcel Panjaitan");
|
||||
payload.put("mid", "71000026521");
|
||||
payload.put("tid", "73001500");
|
||||
|
||||
// Make the API call
|
||||
URL url = new URI(BACKEND_BASE + "/transactions").toURL();
|
||||
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
|
||||
conn.setRequestMethod("POST");
|
||||
conn.setRequestProperty("Content-Type", "application/json");
|
||||
conn.setRequestProperty("Accept", "application/json");
|
||||
conn.setDoOutput(true);
|
||||
|
||||
try (OutputStream os = conn.getOutputStream()) {
|
||||
byte[] input = payload.toString().getBytes("utf-8");
|
||||
os.write(input, 0, input.length);
|
||||
}
|
||||
|
||||
int responseCode = conn.getResponseCode();
|
||||
if (responseCode == 200 || responseCode == 201) {
|
||||
// Read the response
|
||||
BufferedReader br = new BufferedReader(new InputStreamReader(conn.getInputStream(), "utf-8"));
|
||||
StringBuilder response = new StringBuilder();
|
||||
String responseLine;
|
||||
while ((responseLine = br.readLine()) != null) {
|
||||
response.append(responseLine.trim());
|
||||
}
|
||||
|
||||
// Parse the response to get transaction ID
|
||||
JSONObject jsonResponse = new JSONObject(response.toString());
|
||||
JSONObject data = jsonResponse.getJSONObject("data");
|
||||
transactionId = String.valueOf(data.getInt("id"));
|
||||
|
||||
// Now generate QRIS via Midtrans
|
||||
return generateQris(amount);
|
||||
} else {
|
||||
// Read error response
|
||||
BufferedReader br = new BufferedReader(new InputStreamReader(conn.getErrorStream(), "utf-8"));
|
||||
StringBuilder response = new StringBuilder();
|
||||
String responseLine;
|
||||
while ((responseLine = br.readLine()) != null) {
|
||||
response.append(responseLine.trim());
|
||||
}
|
||||
errorMessage = "Error creating transaction: " + response.toString();
|
||||
return false;
|
||||
}
|
||||
} catch (Exception e) {
|
||||
Log.e("MidtransCharge", "Exception: " + e.getMessage(), e);
|
||||
errorMessage = "Unexpected error: " + e.getMessage();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
private boolean generateQris(int amount) {
|
||||
try {
|
||||
// Create QRIS charge JSON payload
|
||||
JSONObject payload = new JSONObject();
|
||||
payload.put("payment_type", "qris");
|
||||
|
||||
JSONObject transactionDetails = new JSONObject();
|
||||
transactionDetails.put("order_id", transactionUuid);
|
||||
transactionDetails.put("gross_amount", amount);
|
||||
payload.put("transaction_details", transactionDetails);
|
||||
|
||||
// Log the request details
|
||||
Log.d("MidtransCharge", "URL: " + MIDTRANS_CHARGE_URL);
|
||||
Log.d("MidtransCharge", "Authorization: " + MIDTRANS_AUTH);
|
||||
Log.d("MidtransCharge", "Accept: application/json");
|
||||
Log.d("MidtransCharge", "Content-Type: application/json");
|
||||
Log.d("MidtransCharge", "X-Override-Notification: " + WEBHOOK_URL);
|
||||
Log.d("MidtransCharge", "Payload: " + payload.toString());
|
||||
|
||||
// Make the API call to Midtrans
|
||||
URL url = new URI(MIDTRANS_CHARGE_URL).toURL();
|
||||
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
|
||||
conn.setRequestMethod("POST");
|
||||
conn.setRequestProperty("Accept", "application/json");
|
||||
conn.setRequestProperty("Content-Type", "application/json");
|
||||
conn.setRequestProperty("Authorization", MIDTRANS_AUTH);
|
||||
conn.setRequestProperty("X-Override-Notification", WEBHOOK_URL);
|
||||
conn.setDoOutput(true);
|
||||
|
||||
try (OutputStream os = conn.getOutputStream()) {
|
||||
byte[] input = payload.toString().getBytes("utf-8");
|
||||
os.write(input, 0, input.length);
|
||||
}
|
||||
|
||||
int responseCode = conn.getResponseCode();
|
||||
if (responseCode == 200 || responseCode == 201) {
|
||||
InputStream inputStream = conn.getInputStream();
|
||||
if (inputStream != null) {
|
||||
BufferedReader br = new BufferedReader(new InputStreamReader(inputStream, "utf-8"));
|
||||
StringBuilder response = new StringBuilder();
|
||||
String responseLine;
|
||||
while ((responseLine = br.readLine()) != null) {
|
||||
response.append(responseLine.trim());
|
||||
}
|
||||
|
||||
// Parse the response
|
||||
midtransResponse = new JSONObject(response.toString());
|
||||
return true;
|
||||
} else {
|
||||
Log.e("MidtransCharge", "HTTP " + responseCode + ": No input stream available");
|
||||
errorMessage = "Error generating QRIS: HTTP " + responseCode + ": No input stream available";
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
InputStream errorStream = conn.getErrorStream();
|
||||
if (errorStream != null) {
|
||||
BufferedReader br = new BufferedReader(new InputStreamReader(errorStream, "utf-8"));
|
||||
StringBuilder errorResponse = new StringBuilder();
|
||||
String responseLine;
|
||||
while ((responseLine = br.readLine()) != null) {
|
||||
errorResponse.append(responseLine.trim());
|
||||
}
|
||||
Log.e("MidtransCharge", "HTTP " + responseCode + ": " + errorResponse.toString());
|
||||
errorMessage = "Error generating QRIS: HTTP " + responseCode + ": " + errorResponse.toString();
|
||||
} else {
|
||||
Log.e("MidtransCharge", "HTTP " + responseCode + ": No error stream available");
|
||||
errorMessage = "Error generating QRIS: HTTP " + responseCode + ": No error stream available";
|
||||
}
|
||||
return false;
|
||||
}
|
||||
} catch (Exception e) {
|
||||
Log.e("MidtransCharge", "Exception: " + e.getMessage(), e);
|
||||
errorMessage = "Unexpected error: " + e.getMessage();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onPostExecute(Boolean success) {
|
||||
if (success && midtransResponse != null) {
|
||||
try {
|
||||
// Extract needed values from midtransResponse
|
||||
JSONObject actions = midtransResponse.getJSONArray("actions").getJSONObject(0);
|
||||
String qrImageUrl = actions.getString("url");
|
||||
|
||||
// Extract transaction_id
|
||||
String transactionId = midtransResponse.getString("transaction_id");
|
||||
String transactionTime = midtransResponse.getString("transaction_time");
|
||||
String acquirer = midtransResponse.getString("acquirer");
|
||||
String merchantId = midtransResponse.getString("merchant_id");
|
||||
String exactGrossAmount = midtransResponse.getString("gross_amount");
|
||||
|
||||
// Log everything before launching activity
|
||||
Log.d("MidtransCharge", "Creating QrisResultActivity intent with:");
|
||||
Log.d("MidtransCharge", "qrImageUrl: " + qrImageUrl);
|
||||
Log.d("MidtransCharge", "amount: " + amount);
|
||||
Log.d("MidtransCharge", "referenceId: " + referenceId);
|
||||
Log.d("MidtransCharge", "transactionUuid (orderId): " + transactionUuid);
|
||||
Log.d("MidtransCharge", "transaction_id: " + transactionId);
|
||||
Log.d("MidtransCharge", "exactGrossAmount: " + exactGrossAmount);
|
||||
|
||||
// Instead of showing QR inline, launch QrisResultActivity
|
||||
Intent intent = new Intent(QrisActivity.this, QrisResultActivity.class);
|
||||
intent.putExtra("qrImageUrl", qrImageUrl);
|
||||
intent.putExtra("amount", amount);
|
||||
intent.putExtra("referenceId", referenceId);
|
||||
intent.putExtra("orderId", transactionUuid); // Order ID
|
||||
intent.putExtra("transactionId", transactionId); // Actual Midtrans transaction_id
|
||||
intent.putExtra("grossAmount", exactGrossAmount); // Exact gross amount from response
|
||||
intent.putExtra("transactionTime", transactionTime); // For timestamp
|
||||
intent.putExtra("acquirer", acquirer);
|
||||
intent.putExtra("merchantId", merchantId);
|
||||
|
||||
try {
|
||||
startActivity(intent);
|
||||
} catch (Exception e) {
|
||||
Log.e("MidtransCharge", "Failed to start QrisResultActivity: " + e.getMessage(), e);
|
||||
Toast.makeText(QrisActivity.this, "Error launching QR display: " + e.getMessage(), Toast.LENGTH_LONG).show();
|
||||
}
|
||||
return;
|
||||
} catch (JSONException e) {
|
||||
Log.e("MidtransCharge", "QRIS response JSON error: " + e.getMessage(), e);
|
||||
Toast.makeText(QrisActivity.this, "Error processing QRIS response", Toast.LENGTH_LONG).show();
|
||||
}
|
||||
} else {
|
||||
String message = (errorMessage != null && !errorMessage.isEmpty()) ? errorMessage : "Unknown error occurred. Please check Logcat for details.";
|
||||
Toast.makeText(QrisActivity.this, message, Toast.LENGTH_LONG).show();
|
||||
initiatePaymentButton.setEnabled(true);
|
||||
}
|
||||
progressBar.setVisibility(View.GONE);
|
||||
}
|
||||
}
|
||||
|
||||
private class DownloadImageTask extends AsyncTask<String, Void, Bitmap> {
|
||||
@Override
|
||||
protected Bitmap doInBackground(String... urls) {
|
||||
String urlDisplay = urls[0];
|
||||
Bitmap bitmap = null;
|
||||
try {
|
||||
URL url = new URI(urlDisplay).toURL();
|
||||
HttpURLConnection connection = (HttpURLConnection) url.openConnection();
|
||||
connection.setDoInput(true);
|
||||
connection.connect();
|
||||
java.io.InputStream input = connection.getInputStream();
|
||||
bitmap = android.graphics.BitmapFactory.decodeStream(input);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return bitmap;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onPostExecute(Bitmap result) {
|
||||
if (result != null) {
|
||||
qrCodeImageView.setImageBitmap(result);
|
||||
} else {
|
||||
Toast.makeText(QrisActivity.this, "Error loading QR code image", Toast.LENGTH_LONG).show();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private class SimulateWebhookTask extends AsyncTask<Void, Void, Boolean> {
|
||||
private String errorMessage;
|
||||
|
||||
@Override
|
||||
protected Boolean doInBackground(Void... voids) {
|
||||
try {
|
||||
// Wait a moment to simulate real-world timing
|
||||
Thread.sleep(1500);
|
||||
|
||||
// Get server key and prepare signature
|
||||
String serverKey = getServerKey();
|
||||
String grossAmount = String.valueOf(amount) + ".00";
|
||||
String signatureKey = generateSignature(
|
||||
transactionUuid,
|
||||
"200",
|
||||
grossAmount,
|
||||
serverKey
|
||||
);
|
||||
|
||||
// Create webhook payload
|
||||
JSONObject payload = new JSONObject();
|
||||
payload.put("transaction_type", "on-us");
|
||||
payload.put("transaction_time", midtransResponse.getString("transaction_time"));
|
||||
payload.put("transaction_status", "settlement");
|
||||
payload.put("transaction_id", midtransResponse.getString("transaction_id"));
|
||||
payload.put("status_message", "midtrans payment notification");
|
||||
payload.put("status_code", "200");
|
||||
payload.put("signature_key", signatureKey);
|
||||
payload.put("settlement_time", midtransResponse.getString("transaction_time"));
|
||||
payload.put("payment_type", "qris");
|
||||
payload.put("order_id", transactionUuid);
|
||||
payload.put("merchant_id", midtransResponse.getString("merchant_id"));
|
||||
payload.put("issuer", midtransResponse.getString("acquirer"));
|
||||
payload.put("gross_amount", grossAmount);
|
||||
payload.put("fraud_status", "accept");
|
||||
payload.put("currency", "IDR");
|
||||
payload.put("acquirer", midtransResponse.getString("acquirer"));
|
||||
payload.put("shopeepay_reference_number", "");
|
||||
payload.put("reference_id", referenceId);
|
||||
|
||||
// Call the webhook URL
|
||||
URL url = new URI(WEBHOOK_URL).toURL();
|
||||
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
|
||||
conn.setRequestMethod("POST");
|
||||
conn.setRequestProperty("Content-Type", "application/json");
|
||||
conn.setRequestProperty("Accept", "application/json");
|
||||
conn.setDoOutput(true);
|
||||
|
||||
try (OutputStream os = conn.getOutputStream()) {
|
||||
byte[] input = payload.toString().getBytes("utf-8");
|
||||
os.write(input, 0, input.length);
|
||||
}
|
||||
|
||||
int responseCode = conn.getResponseCode();
|
||||
if (responseCode == 200 || responseCode == 201) {
|
||||
// Wait briefly to allow the backend to process
|
||||
Thread.sleep(2000);
|
||||
return checkTransactionStatus();
|
||||
} else {
|
||||
// Read error response
|
||||
BufferedReader br = new BufferedReader(new InputStreamReader(conn.getErrorStream(), "utf-8"));
|
||||
StringBuilder response = new StringBuilder();
|
||||
String responseLine;
|
||||
while ((responseLine = br.readLine()) != null) {
|
||||
response.append(responseLine.trim());
|
||||
}
|
||||
errorMessage = "Error simulating payment: " + response.toString();
|
||||
return false;
|
||||
}
|
||||
} catch (Exception e) {
|
||||
errorMessage = "Error: " + e.getMessage();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
private boolean checkTransactionStatus() {
|
||||
try {
|
||||
// Check transaction status
|
||||
URL url = new URI(BACKEND_BASE + "/transactions/" + transactionId).toURL();
|
||||
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
|
||||
conn.setRequestMethod("GET");
|
||||
conn.setRequestProperty("Accept", "application/json");
|
||||
|
||||
int responseCode = conn.getResponseCode();
|
||||
if (responseCode == 200) {
|
||||
// Read the response
|
||||
BufferedReader br = new BufferedReader(new InputStreamReader(conn.getInputStream(), "utf-8"));
|
||||
StringBuilder response = new StringBuilder();
|
||||
String responseLine;
|
||||
while ((responseLine = br.readLine()) != null) {
|
||||
response.append(responseLine.trim());
|
||||
}
|
||||
|
||||
// Parse the response
|
||||
JSONObject jsonResponse = new JSONObject(response.toString());
|
||||
JSONObject data = jsonResponse.getJSONObject("data");
|
||||
String status = data.getString("status");
|
||||
|
||||
return status.equalsIgnoreCase("SUCCESS");
|
||||
} else {
|
||||
errorMessage = "Error checking transaction status. HTTP response code: " + responseCode;
|
||||
return false;
|
||||
}
|
||||
} catch (Exception e) {
|
||||
errorMessage = "Error checking transaction status: " + e.getMessage();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onPostExecute(Boolean success) {
|
||||
if (success) {
|
||||
showSuccessScreen();
|
||||
} else {
|
||||
String message = (errorMessage != null && !errorMessage.isEmpty()) ? errorMessage : "Unknown error occurred. Please check Logcat for details.";
|
||||
Toast.makeText(QrisActivity.this, message, Toast.LENGTH_LONG).show();
|
||||
simulatePaymentButton.setEnabled(true);
|
||||
}
|
||||
progressBar.setVisibility(View.GONE);
|
||||
}
|
||||
}
|
||||
}
|
@ -95,10 +95,10 @@ public class ReceiptActivity extends AppCompatActivity {
|
||||
}
|
||||
|
||||
private void setupClickListeners() {
|
||||
// Back navigation
|
||||
backNavigation.setOnClickListener(v -> navigateBack());
|
||||
backArrow.setOnClickListener(v -> navigateBack());
|
||||
toolbarTitle.setOnClickListener(v -> navigateBack());
|
||||
// Back navigation - Goes back to previous activity (PaymentActivity)
|
||||
backNavigation.setOnClickListener(v -> navigateBackToPrevious());
|
||||
backArrow.setOnClickListener(v -> navigateBackToPrevious());
|
||||
toolbarTitle.setOnClickListener(v -> navigateBackToPrevious());
|
||||
|
||||
// Action buttons
|
||||
printButton.setOnClickListener(v -> handlePrintReceipt());
|
||||
@ -191,24 +191,43 @@ public class ReceiptActivity extends AppCompatActivity {
|
||||
}
|
||||
|
||||
private void handleFinish() {
|
||||
// Finish and return to main screen
|
||||
navigateBack();
|
||||
// Navigate to MainActivity/Home Page when "Selesai" button is pressed
|
||||
navigateToHomePage();
|
||||
}
|
||||
|
||||
private void navigateBack() {
|
||||
// You can navigate back to main activity or finish
|
||||
private void navigateBackToPrevious() {
|
||||
// Navigate back to PaymentActivity (previous activity)
|
||||
Intent intent = new Intent(this, PaymentActivity.class);
|
||||
intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_NEW_TASK);
|
||||
startActivity(intent);
|
||||
finish();
|
||||
}
|
||||
|
||||
private void navigateToHomePage() {
|
||||
// Navigate to MainActivity/Home Page when "Selesai" button is pressed
|
||||
Intent intent = new Intent(this, MainActivity.class);
|
||||
|
||||
// Clear all previous activities from the stack and start fresh
|
||||
intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK | Intent.FLAG_ACTIVITY_NEW_TASK);
|
||||
|
||||
// Optional: Add success message to show in MainActivity
|
||||
intent.putExtra("transaction_completed", true);
|
||||
intent.putExtra("transaction_amount", getIntent().getStringExtra("transaction_amount"));
|
||||
|
||||
startActivity(intent);
|
||||
finish();
|
||||
|
||||
// Show success message
|
||||
showToast("Transaksi berhasil diselesaikan!");
|
||||
}
|
||||
|
||||
private void showToast(String message) {
|
||||
android.widget.Toast.makeText(this, message, android.widget.Toast.LENGTH_SHORT).show();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onBackPressed() {
|
||||
navigateBack();
|
||||
// Back button behavior - goes back to previous activity
|
||||
navigateBackToPrevious();
|
||||
}
|
||||
}
|
227
app/src/main/res/layout/activity_qris.xml
Normal file
227
app/src/main/res/layout/activity_qris.xml
Normal file
@ -0,0 +1,227 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<androidx.coordinatorlayout.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent">
|
||||
|
||||
<com.google.android.material.appbar.AppBarLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content">
|
||||
|
||||
<androidx.appcompat.widget.Toolbar
|
||||
android:id="@+id/toolbar"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="?attr/actionBarSize"
|
||||
android:background="?attr/colorPrimary"
|
||||
android:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar"
|
||||
app:popupTheme="@style/ThemeOverlay.AppCompat.Light"
|
||||
app:title="QRIS Payment" />
|
||||
|
||||
</com.google.android.material.appbar.AppBarLayout>
|
||||
|
||||
<androidx.core.widget.NestedScrollView
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
app:layout_behavior="@string/appbar_scrolling_view_behavior">
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:orientation="vertical"
|
||||
android:padding="16dp">
|
||||
|
||||
<ProgressBar
|
||||
android:id="@+id/progressBar"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center_horizontal"
|
||||
android:visibility="gone" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/statusTextView"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginBottom="16dp"
|
||||
android:gravity="center"
|
||||
android:text="Ready to make a payment"
|
||||
android:textSize="18sp" />
|
||||
|
||||
<!-- Initial Payment Form -->
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical">
|
||||
|
||||
<androidx.cardview.widget.CardView
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_margin="8dp"
|
||||
app:cardBackgroundColor="@color/light_blue"
|
||||
app:cardCornerRadius="8dp"
|
||||
app:cardElevation="4dp">
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical"
|
||||
android:padding="16dp">
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="Amount"
|
||||
android:textColor="@color/primary_blue"
|
||||
android:textSize="16sp" />
|
||||
|
||||
<EditText
|
||||
android:id="@+id/editTextAmount"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="8dp"
|
||||
android:hint="Enter amount"
|
||||
android:inputType="number"
|
||||
android:maxLength="12"
|
||||
android:importantForAutofill="no"
|
||||
android:singleLine="true"
|
||||
android:textColor="@color/primary_blue"
|
||||
android:textSize="24sp"
|
||||
android:textStyle="bold"
|
||||
android:gravity="end" />
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="16dp"
|
||||
android:text="Reference ID"
|
||||
android:textColor="@color/primary_blue"
|
||||
android:textSize="16sp" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/referenceIdTextView"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="8dp"
|
||||
android:text="ref-abcd1234"
|
||||
android:textColor="@color/primary_blue"
|
||||
android:textSize="16sp" />
|
||||
</LinearLayout>
|
||||
</androidx.cardview.widget.CardView>
|
||||
|
||||
<Button
|
||||
android:id="@+id/initiatePaymentButton"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_margin="8dp"
|
||||
android:backgroundTint="@color/primary_blue"
|
||||
android:text="Start Payment" />
|
||||
</LinearLayout>
|
||||
|
||||
<!-- QR Code and Payment Details -->
|
||||
<LinearLayout
|
||||
android:id="@+id/paymentDetailsLayout"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical"
|
||||
android:visibility="gone">
|
||||
|
||||
<androidx.cardview.widget.CardView
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_margin="8dp"
|
||||
app:cardCornerRadius="8dp"
|
||||
app:cardElevation="4dp">
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:gravity="center_horizontal"
|
||||
android:orientation="vertical"
|
||||
android:padding="16dp">
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/qrCodeImageView"
|
||||
android:layout_width="250dp"
|
||||
android:layout_height="250dp"
|
||||
android:contentDescription="QRIS Code"
|
||||
android:scaleType="fitCenter" />
|
||||
|
||||
<TextView
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="16dp"
|
||||
android:gravity="center"
|
||||
android:text="Scan with your banking app or e-wallet to pay"
|
||||
android:textSize="14sp" />
|
||||
</LinearLayout>
|
||||
</androidx.cardview.widget.CardView>
|
||||
|
||||
<Button
|
||||
android:id="@+id/simulatePaymentButton"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_margin="8dp"
|
||||
android:backgroundTint="@color/accent_green"
|
||||
android:text="Confirm Payment" />
|
||||
</LinearLayout>
|
||||
|
||||
<!-- Payment Success -->
|
||||
<LinearLayout
|
||||
android:id="@+id/paymentSuccessLayout"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical"
|
||||
android:visibility="gone">
|
||||
|
||||
<androidx.cardview.widget.CardView
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_margin="8dp"
|
||||
app:cardBackgroundColor="@color/light_gray"
|
||||
app:cardCornerRadius="8dp"
|
||||
app:cardElevation="4dp">
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:gravity="center_horizontal"
|
||||
android:orientation="vertical"
|
||||
android:padding="16dp">
|
||||
|
||||
<ImageView
|
||||
android:layout_width="64dp"
|
||||
android:layout_height="64dp"
|
||||
android:contentDescription="Success Icon"
|
||||
android:src="@android:drawable/ic_dialog_info"
|
||||
android:tint="@color/accent_green" />
|
||||
|
||||
<TextView
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="16dp"
|
||||
android:gravity="center"
|
||||
android:text="Payment Successful!"
|
||||
android:textColor="@color/accent_green"
|
||||
android:textSize="20sp"
|
||||
android:textStyle="bold" />
|
||||
|
||||
<TextView
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="8dp"
|
||||
android:gravity="center"
|
||||
android:text="Your transaction has been completed successfully."
|
||||
android:textSize="14sp" />
|
||||
</LinearLayout>
|
||||
</androidx.cardview.widget.CardView>
|
||||
|
||||
<Button
|
||||
android:id="@+id/returnToMainButton"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_margin="8dp"
|
||||
android:backgroundTint="@color/primary_blue"
|
||||
android:text="Return to Main" />
|
||||
</LinearLayout>
|
||||
</LinearLayout>
|
||||
</androidx.core.widget.NestedScrollView>
|
||||
</androidx.coordinatorlayout.widget.CoordinatorLayout>
|
Loading…
x
Reference in New Issue
Block a user