safepoint Detail transaksi
This commit is contained in:
parent
d4245c5906
commit
c56cae64b9
@ -140,84 +140,85 @@ public class ReceiptActivity extends AppCompatActivity {
|
|||||||
String tid = intent.getStringExtra("tid");
|
String tid = intent.getStringExtra("tid");
|
||||||
|
|
||||||
// Log received data for debugging
|
// Log received data for debugging
|
||||||
Log.d("ReceiptActivity", "amount: " + amount);
|
Log.d("ReceiptActivity", "🔍 RECEIVED DATA:");
|
||||||
Log.d("ReceiptActivity", "grossAmount: " + grossAmount);
|
Log.d("ReceiptActivity", " amount: " + amount);
|
||||||
Log.d("ReceiptActivity", "merchantName: " + merchantNameStr);
|
Log.d("ReceiptActivity", " referenceId: " + referenceId);
|
||||||
Log.d("ReceiptActivity", "referenceId: " + referenceId);
|
Log.d("ReceiptActivity", " orderId: " + orderId);
|
||||||
Log.d("ReceiptActivity", "createdAt: " + createdAt);
|
Log.d("ReceiptActivity", " channelCode: " + channelCode);
|
||||||
Log.d("ReceiptActivity", "channelCode: " + channelCode);
|
Log.d("ReceiptActivity", " acquirer (from intent): " + acquirer);
|
||||||
Log.d("ReceiptActivity", "acquirer: " + acquirer);
|
Log.d("ReceiptActivity", " createdAt: " + createdAt);
|
||||||
Log.d("ReceiptActivity", "mid: " + mid);
|
|
||||||
Log.d("ReceiptActivity", "tid: " + tid);
|
|
||||||
|
|
||||||
// 1. Set merchant data with defaults
|
// 1. Set merchant data with defaults
|
||||||
merchantName.setText(merchantNameStr != null ? merchantNameStr : "Marcel Panjaitan");
|
merchantName.setText(merchantNameStr != null ? merchantNameStr : "Marcel Panjaitan");
|
||||||
merchantLocation.setText(merchantLocationStr != null ? merchantLocationStr : "Jakarta, Indonesia");
|
merchantLocation.setText(merchantLocationStr != null ? merchantLocationStr : "Jakarta, Indonesia");
|
||||||
|
|
||||||
// 2. Set MID and TID - prioritize from intent, then defaults
|
// 2. Set MID and TID
|
||||||
midText.setText(mid != null ? mid : "71000026521");
|
midText.setText(mid != null ? mid : "71000026521");
|
||||||
tidText.setText(tid != null ? tid : "73001500");
|
tidText.setText(tid != null ? tid : "73001500");
|
||||||
|
|
||||||
// 3. Set transaction number - prioritize reference_id
|
// 3. Set transaction number
|
||||||
String displayTransactionNumber = null;
|
String displayTransactionNumber = null;
|
||||||
if (referenceId != null && !referenceId.isEmpty()) {
|
if (referenceId != null && !referenceId.isEmpty()) {
|
||||||
displayTransactionNumber = referenceId;
|
displayTransactionNumber = referenceId;
|
||||||
Log.d("ReceiptActivity", "Using reference_id as transaction number: " + referenceId);
|
|
||||||
} else if (transactionId != null && !transactionId.isEmpty()) {
|
} else if (transactionId != null && !transactionId.isEmpty()) {
|
||||||
displayTransactionNumber = transactionId;
|
displayTransactionNumber = transactionId;
|
||||||
Log.d("ReceiptActivity", "Using transaction_id as transaction number: " + transactionId);
|
|
||||||
} else if (orderId != null && !orderId.isEmpty()) {
|
} else if (orderId != null && !orderId.isEmpty()) {
|
||||||
displayTransactionNumber = orderId;
|
displayTransactionNumber = orderId;
|
||||||
Log.d("ReceiptActivity", "Using order_id as transaction number: " + orderId);
|
|
||||||
}
|
}
|
||||||
transactionNumber.setText(displayTransactionNumber != null ? displayTransactionNumber : "N/A");
|
transactionNumber.setText(displayTransactionNumber != null ? displayTransactionNumber : "N/A");
|
||||||
|
|
||||||
// 4. Set transaction date - prioritize createdAt, format as dd/MM/yyyy HH:mm
|
// 4. Set transaction date
|
||||||
String displayDate = null;
|
String displayDate = null;
|
||||||
if (createdAt != null && !createdAt.isEmpty()) {
|
if (createdAt != null && !createdAt.isEmpty()) {
|
||||||
displayDate = formatDateFromCreatedAt(createdAt);
|
displayDate = formatDateFromCreatedAt(createdAt);
|
||||||
Log.d("ReceiptActivity", "Formatted createdAt: " + createdAt + " -> " + displayDate);
|
|
||||||
} else if (transactionDateStr != null && !transactionDateStr.isEmpty()) {
|
} else if (transactionDateStr != null && !transactionDateStr.isEmpty()) {
|
||||||
displayDate = transactionDateStr;
|
displayDate = transactionDateStr;
|
||||||
Log.d("ReceiptActivity", "Using provided transaction_date: " + transactionDateStr);
|
|
||||||
} else {
|
} else {
|
||||||
displayDate = getCurrentDateTime();
|
displayDate = getCurrentDateTime();
|
||||||
Log.d("ReceiptActivity", "Using current datetime: " + displayDate);
|
|
||||||
}
|
}
|
||||||
transactionDate.setText(displayDate);
|
transactionDate.setText(displayDate);
|
||||||
|
|
||||||
// 5. Set payment method - use channel_code mapping
|
// 5. Set payment method
|
||||||
String displayPaymentMethod = getPaymentMethodFromChannelCode(channelCode, paymentMethodStr);
|
String displayPaymentMethod = getPaymentMethodFromChannelCode(channelCode, paymentMethodStr);
|
||||||
paymentMethod.setText(displayPaymentMethod);
|
paymentMethod.setText(displayPaymentMethod);
|
||||||
Log.d("ReceiptActivity", "Payment method: " + displayPaymentMethod + " (from channel: " + channelCode + ")");
|
|
||||||
|
|
||||||
// 6. Set card type - use acquirer with comprehensive mapping
|
// 6. ✅ IMPROVED: Enhanced card type detection for QRIS
|
||||||
// For QRIS, we need to get the actual acquirer (GoPay, OVO, DANA, etc.)
|
String displayCardType = null;
|
||||||
String displayCardType = getCardTypeFromAcquirer(acquirer, channelCode, cardTypeStr);
|
|
||||||
|
|
||||||
// Special handling for QRIS - if we only have "QRIS" or "qris", try to get real acquirer
|
if (channelCode != null && channelCode.equalsIgnoreCase("QRIS")) {
|
||||||
if (displayCardType.equalsIgnoreCase("QRIS") && channelCode != null && channelCode.equalsIgnoreCase("QRIS")) {
|
Log.d("ReceiptActivity", "🔍 QRIS transaction detected - searching for real acquirer");
|
||||||
// For QRIS transactions, we should try to determine the actual acquirer
|
|
||||||
// This might require additional API call or webhook data parsing
|
// For QRIS, try to get real acquirer from webhook data
|
||||||
Log.w("ReceiptActivity", "QRIS transaction detected but no specific acquirer found. Using default.");
|
if (referenceId != null && !referenceId.isEmpty()) {
|
||||||
// In production, this should fetch the real acquirer from transaction status API
|
String realAcquirer = fetchRealAcquirerSync(referenceId);
|
||||||
displayCardType = acquirer != null && !acquirer.equalsIgnoreCase("qris") ?
|
if (realAcquirer != null && !realAcquirer.isEmpty() && !realAcquirer.equalsIgnoreCase("qris")) {
|
||||||
getCardTypeFromAcquirer(acquirer, channelCode, cardTypeStr) : "GoPay"; // Default QRIS acquirer
|
displayCardType = getCardTypeFromAcquirer(realAcquirer, null, null);
|
||||||
|
Log.d("ReceiptActivity", "✅ QRIS real acquirer found: " + realAcquirer + " -> " + displayCardType);
|
||||||
|
} else {
|
||||||
|
Log.w("ReceiptActivity", "⚠️ QRIS real acquirer not found, using generic QRIS");
|
||||||
|
displayCardType = "QRIS";
|
||||||
|
|
||||||
|
// Start async search for better results
|
||||||
|
fetchRealAcquirerFromWebhook(referenceId);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
displayCardType = "QRIS";
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// Non-QRIS transaction
|
||||||
|
displayCardType = getCardTypeFromAcquirer(acquirer, channelCode, cardTypeStr);
|
||||||
}
|
}
|
||||||
|
|
||||||
cardType.setText(displayCardType);
|
cardType.setText(displayCardType);
|
||||||
Log.d("ReceiptActivity", "Card type: " + displayCardType + " (from acquirer: " + acquirer + ")");
|
Log.d("ReceiptActivity", "💳 FINAL CARD TYPE: " + displayCardType);
|
||||||
|
|
||||||
// 7. Format and set amounts - prioritize amount over grossAmount
|
// 7. Format and set amounts
|
||||||
setAmountData(amount, grossAmount);
|
setAmountData(amount, grossAmount);
|
||||||
|
|
||||||
Log.d("ReceiptActivity", "=== TRANSACTION DATA LOADED ===");
|
Log.d("ReceiptActivity", "=== TRANSACTION DATA LOADED ===");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Format date from createdAt field (yyyy-MM-dd HH:mm:ss) to Indonesian format (dd/MM/yyyy HH:mm)
|
|
||||||
*/
|
|
||||||
private String formatDateFromCreatedAt(String createdAt) {
|
private String formatDateFromCreatedAt(String createdAt) {
|
||||||
try {
|
try {
|
||||||
// Input format from database: "yyyy-MM-dd HH:mm:ss"
|
// Input format from database: "yyyy-MM-dd HH:mm:ss"
|
||||||
@ -291,83 +292,135 @@ public class ReceiptActivity extends AppCompatActivity {
|
|||||||
private String getCardTypeFromAcquirer(String acquirer, String channelCode, String fallbackCardType) {
|
private String getCardTypeFromAcquirer(String acquirer, String channelCode, String fallbackCardType) {
|
||||||
// STEP 1: If we have a valid acquirer that's not generic "qris", use it
|
// STEP 1: If we have a valid acquirer that's not generic "qris", use it
|
||||||
if (acquirer != null && !acquirer.isEmpty() && !acquirer.equalsIgnoreCase("qris")) {
|
if (acquirer != null && !acquirer.isEmpty() && !acquirer.equalsIgnoreCase("qris")) {
|
||||||
String acq = acquirer.toLowerCase();
|
String acq = acquirer.toLowerCase().trim();
|
||||||
|
|
||||||
// Comprehensive acquirer mapping based on Midtrans
|
Log.d("ReceiptActivity", "🔍 Mapping acquirer: '" + acquirer + "' -> '" + acq + "'");
|
||||||
|
|
||||||
|
// ✅ COMPREHENSIVE acquirer mapping (case-insensitive)
|
||||||
switch (acq) {
|
switch (acq) {
|
||||||
// E-Wallet acquirers
|
// E-Wallet acquirers (most common for QRIS)
|
||||||
case "gopay": return "GoPay";
|
case "gopay":
|
||||||
case "shopeepay": return "ShopeePay";
|
case "go-pay":
|
||||||
|
case "gojek": return "GoPay";
|
||||||
|
|
||||||
|
case "shopeepay":
|
||||||
|
case "shopee_pay":
|
||||||
|
case "shopee": return "ShopeePay";
|
||||||
|
|
||||||
case "ovo": return "OVO";
|
case "ovo": return "OVO";
|
||||||
|
|
||||||
case "dana": return "DANA";
|
case "dana": return "DANA";
|
||||||
case "linkaja": return "LinkAja";
|
|
||||||
case "jenius": return "Jenius";
|
case "linkaja":
|
||||||
case "kaspro": return "KasPro";
|
case "link_aja":
|
||||||
|
case "tcash": return "LinkAja";
|
||||||
|
|
||||||
|
case "jenius":
|
||||||
|
case "btpn": return "Jenius";
|
||||||
|
|
||||||
|
case "kaspro":
|
||||||
|
case "kas_pro": return "KasPro";
|
||||||
|
|
||||||
|
case "sakuku":
|
||||||
|
case "saku_ku": return "SakuKu";
|
||||||
|
|
||||||
|
case "doku":
|
||||||
|
case "doku_wallet": return "DOKU";
|
||||||
|
|
||||||
|
case "paymi":
|
||||||
|
case "pay_mi": return "PayMi";
|
||||||
|
|
||||||
|
case "isaku":
|
||||||
|
case "i_saku": return "i.Saku";
|
||||||
|
|
||||||
// Bank acquirers
|
// Bank acquirers
|
||||||
case "bca": return "BCA";
|
case "bca":
|
||||||
|
case "bank_bca": return "BCA";
|
||||||
|
|
||||||
case "mandiri":
|
case "mandiri":
|
||||||
|
case "bank_mandiri":
|
||||||
case "mandiri_bill": return "Mandiri";
|
case "mandiri_bill": return "Mandiri";
|
||||||
|
|
||||||
case "bni":
|
case "bni":
|
||||||
|
case "bank_bni":
|
||||||
case "bni_va": return "BNI";
|
case "bni_va": return "BNI";
|
||||||
|
|
||||||
case "bri":
|
case "bri":
|
||||||
|
case "bank_bri":
|
||||||
case "bri_va": return "BRI";
|
case "bri_va": return "BRI";
|
||||||
|
|
||||||
case "permata":
|
case "permata":
|
||||||
|
case "bank_permata":
|
||||||
case "permata_va": return "Permata";
|
case "permata_va": return "Permata";
|
||||||
|
|
||||||
case "cimb":
|
case "cimb":
|
||||||
|
case "cimb_niaga":
|
||||||
|
case "bank_cimb":
|
||||||
case "cimb_va": return "CIMB Niaga";
|
case "cimb_va": return "CIMB Niaga";
|
||||||
|
|
||||||
case "danamon":
|
case "danamon":
|
||||||
|
case "bank_danamon":
|
||||||
case "danamon_va": return "Danamon";
|
case "danamon_va": return "Danamon";
|
||||||
|
|
||||||
case "bsi":
|
case "bsi":
|
||||||
case "bsi_va": return "BSI";
|
case "bank_bsi":
|
||||||
case "maybank": return "Maybank";
|
case "bsi_va":
|
||||||
|
case "syariah_indonesia": return "BSI";
|
||||||
|
|
||||||
|
case "maybank":
|
||||||
|
case "bank_maybank": return "Maybank";
|
||||||
|
|
||||||
|
case "bca_digital":
|
||||||
|
case "blu": return "BCA Digital";
|
||||||
|
|
||||||
|
case "jago":
|
||||||
|
case "bank_jago": return "Bank Jago";
|
||||||
|
|
||||||
|
case "seabank":
|
||||||
|
case "sea_bank": return "SeaBank";
|
||||||
|
|
||||||
// Credit card acquirers
|
// Credit card acquirers
|
||||||
case "visa": return "Visa";
|
case "visa": return "Visa";
|
||||||
case "mastercard": return "Mastercard";
|
case "mastercard":
|
||||||
|
case "master_card": return "Mastercard";
|
||||||
case "jcb": return "JCB";
|
case "jcb": return "JCB";
|
||||||
case "amex":
|
case "amex":
|
||||||
case "american_express": return "American Express";
|
case "american_express": return "American Express";
|
||||||
|
case "discover": return "Discover";
|
||||||
|
case "unionpay":
|
||||||
|
case "union_pay": return "UnionPay";
|
||||||
|
|
||||||
// Over-the-counter
|
// Over-the-counter
|
||||||
case "alfamart": return "Alfamart";
|
case "alfamart":
|
||||||
case "indomaret": return "Indomaret";
|
case "alfa_mart": return "Alfamart";
|
||||||
|
case "indomaret":
|
||||||
|
case "indo_maret": return "Indomaret";
|
||||||
|
case "pos_indonesia": return "Pos Indonesia";
|
||||||
|
|
||||||
// Buy now pay later
|
// Buy now pay later
|
||||||
case "akulaku": return "Akulaku";
|
case "akulaku": return "Akulaku";
|
||||||
case "kredivo": return "Kredivo";
|
case "kredivo": return "Kredivo";
|
||||||
case "indodana": return "Indodana";
|
case "indodana":
|
||||||
|
case "indo_dana": return "Indodana";
|
||||||
|
case "traveloka_paylater":
|
||||||
|
case "traveloka": return "Traveloka PayLater";
|
||||||
|
case "atome": return "Atome";
|
||||||
|
|
||||||
default:
|
default:
|
||||||
// Return capitalized version of acquirer if not in mapping
|
// Return capitalized version of acquirer if not in mapping
|
||||||
return capitalizeFirstLetter(acquirer);
|
String capitalized = capitalizeFirstLetter(acquirer);
|
||||||
|
Log.d("ReceiptActivity", "🔤 Using capitalized acquirer: " + capitalized);
|
||||||
|
return capitalized;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// STEP 2: For QRIS transactions, try to fetch real acquirer from webhook data
|
// STEP 2: Fallback based on channel code
|
||||||
if (channelCode != null && channelCode.equalsIgnoreCase("QRIS")) {
|
|
||||||
String referenceId = getIntent().getStringExtra("reference_id");
|
|
||||||
if (referenceId != null && !referenceId.isEmpty()) {
|
|
||||||
Log.d("ReceiptActivity", "🔍 QRIS detected, fetching real acquirer for: " + referenceId);
|
|
||||||
|
|
||||||
// Try to get real acquirer from webhook data synchronously for initial load
|
|
||||||
String realAcquirer = fetchRealAcquirerSync(referenceId);
|
|
||||||
if (realAcquirer != null && !realAcquirer.isEmpty() && !realAcquirer.equalsIgnoreCase("qris")) {
|
|
||||||
Log.d("ReceiptActivity", "✅ Found real acquirer synchronously: " + realAcquirer);
|
|
||||||
return getCardTypeFromAcquirer(realAcquirer, null, null);
|
|
||||||
}
|
|
||||||
|
|
||||||
// If sync fetch failed, try async and show generic QRIS for now
|
|
||||||
fetchRealAcquirerFromWebhook(referenceId);
|
|
||||||
return "QRIS"; // ✅ FIXED: Show QRIS instead of defaulting to GoPay
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// STEP 3: Fallback based on channel code
|
|
||||||
if (channelCode != null && !channelCode.isEmpty()) {
|
if (channelCode != null && !channelCode.isEmpty()) {
|
||||||
String code = channelCode.toUpperCase();
|
String code = channelCode.toUpperCase();
|
||||||
|
Log.d("ReceiptActivity", "🔍 Using channel code fallback: " + code);
|
||||||
|
|
||||||
switch (code) {
|
switch (code) {
|
||||||
case "QRIS": return "QRIS"; // ✅ FIXED: Generic QRIS instead of GoPay
|
case "QRIS": return "QRIS"; // Generic QRIS
|
||||||
case "DEBIT": return "Debit";
|
case "DEBIT": return "Debit";
|
||||||
case "CREDIT": return "Credit";
|
case "CREDIT": return "Credit";
|
||||||
case "BCA": return "BCA";
|
case "BCA": return "BCA";
|
||||||
@ -378,23 +431,26 @@ public class ReceiptActivity extends AppCompatActivity {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// STEP 4: Final fallback
|
// STEP 3: Final fallback
|
||||||
return fallbackCardType != null ? fallbackCardType : "Unknown"; // ✅ FIXED: Unknown instead of GoPay
|
String result = fallbackCardType != null ? fallbackCardType : "Unknown";
|
||||||
|
Log.d("ReceiptActivity", "🔍 Using final fallback: " + result);
|
||||||
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
private String fetchRealAcquirerSync(String referenceId) {
|
private String fetchRealAcquirerSync(String referenceId) {
|
||||||
try {
|
try {
|
||||||
Log.d("ReceiptActivity", "🔍 Sync search for acquirer: " + referenceId);
|
Log.d("ReceiptActivity", "🔍 Sync search for acquirer: " + referenceId);
|
||||||
|
|
||||||
String queryUrl = "https://be-edc.msvc.app/api-logs?limit=50&sortOrder=DESC&sortColumn=created_at";
|
// ✅ IMPROVED: Search with broader scope for better matches
|
||||||
|
String queryUrl = "https://be-edc.msvc.app/api-logs?limit=100&sortOrder=DESC&sortColumn=created_at";
|
||||||
|
|
||||||
URL url = new URL(queryUrl);
|
URL url = new URL(queryUrl);
|
||||||
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
|
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
|
||||||
conn.setRequestMethod("GET");
|
conn.setRequestMethod("GET");
|
||||||
conn.setRequestProperty("Accept", "application/json");
|
conn.setRequestProperty("Accept", "application/json");
|
||||||
conn.setRequestProperty("User-Agent", "BDKIPOCApp/1.0");
|
conn.setRequestProperty("User-Agent", "BDKIPOCApp/1.0");
|
||||||
conn.setConnectTimeout(5000); // Short timeout for sync call
|
conn.setConnectTimeout(8000); // Slightly longer timeout for better results
|
||||||
conn.setReadTimeout(5000);
|
conn.setReadTimeout(8000);
|
||||||
|
|
||||||
if (conn.getResponseCode() == 200) {
|
if (conn.getResponseCode() == 200) {
|
||||||
BufferedReader br = new BufferedReader(new InputStreamReader(conn.getInputStream()));
|
BufferedReader br = new BufferedReader(new InputStreamReader(conn.getInputStream()));
|
||||||
@ -408,54 +464,27 @@ public class ReceiptActivity extends AppCompatActivity {
|
|||||||
org.json.JSONArray results = json.optJSONArray("results");
|
org.json.JSONArray results = json.optJSONArray("results");
|
||||||
|
|
||||||
if (results != null && results.length() > 0) {
|
if (results != null && results.length() > 0) {
|
||||||
// Search for the most recent settlement/success transaction
|
Log.d("ReceiptActivity", "📊 Sync analyzing " + results.length() + " webhook logs");
|
||||||
for (int i = 0; i < results.length(); i++) {
|
|
||||||
org.json.JSONObject log = results.getJSONObject(i);
|
|
||||||
org.json.JSONObject reqBody = log.optJSONObject("request_body");
|
|
||||||
|
|
||||||
if (reqBody != null) {
|
// ✅ PRIORITY SEARCH: Look for settlement first, then pending, then any
|
||||||
String logReferenceId = reqBody.optString("reference_id", "");
|
String[] searchPriority = {"settlement", "capture", "success", "pending", ""};
|
||||||
String logTransactionStatus = reqBody.optString("transaction_status", "");
|
|
||||||
String logAcquirer = reqBody.optString("acquirer", "");
|
|
||||||
String logIssuer = reqBody.optString("issuer", "");
|
|
||||||
|
|
||||||
// Check for direct reference match
|
for (String status : searchPriority) {
|
||||||
boolean isDirectMatch = referenceId.equals(logReferenceId);
|
String[] targetStatuses = status.isEmpty() ? new String[]{} : new String[]{status};
|
||||||
|
String foundAcquirer = searchLogsByStatus(results, referenceId, targetStatuses);
|
||||||
|
|
||||||
// Check custom_field1 for refresh tracking
|
if (foundAcquirer != null && !foundAcquirer.isEmpty() && !foundAcquirer.equalsIgnoreCase("qris")) {
|
||||||
boolean isRefreshMatch = false;
|
Log.d("ReceiptActivity", "🎯 Sync found acquirer: " + foundAcquirer +
|
||||||
String customField1 = reqBody.optString("custom_field1", "");
|
" (priority: " + (status.isEmpty() ? "any" : status) + ")");
|
||||||
if (!customField1.isEmpty()) {
|
return foundAcquirer;
|
||||||
try {
|
|
||||||
org.json.JSONObject customData = new org.json.JSONObject(customField1);
|
|
||||||
String originalReference = customData.optString("original_reference", "");
|
|
||||||
String appReferenceId = customData.optString("app_reference_id", "");
|
|
||||||
if (referenceId.equals(originalReference) || referenceId.equals(appReferenceId)) {
|
|
||||||
isRefreshMatch = true;
|
|
||||||
}
|
|
||||||
} catch (org.json.JSONException e) {
|
|
||||||
// Ignore parsing errors
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check if this log matches our reference
|
|
||||||
if (isDirectMatch || isRefreshMatch) {
|
|
||||||
// Prioritize settlement/success status
|
|
||||||
if (logTransactionStatus.equals("settlement") ||
|
|
||||||
logTransactionStatus.equals("capture") ||
|
|
||||||
logTransactionStatus.equals("success")) {
|
|
||||||
|
|
||||||
// Extract acquirer (prefer acquirer field over issuer)
|
|
||||||
String foundAcquirer = !logAcquirer.isEmpty() ? logAcquirer : logIssuer;
|
|
||||||
if (!foundAcquirer.isEmpty() && !foundAcquirer.equalsIgnoreCase("qris")) {
|
|
||||||
Log.d("ReceiptActivity", "📋 Sync found acquirer: " + foundAcquirer + " (status: " + logTransactionStatus + ")");
|
|
||||||
return foundAcquirer;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Log.w("ReceiptActivity", "⚠️ Sync search completed but no valid acquirer found");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
} else {
|
||||||
|
Log.w("ReceiptActivity", "⚠️ Sync API call failed with code: " + conn.getResponseCode());
|
||||||
}
|
}
|
||||||
|
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
@ -470,15 +499,15 @@ public class ReceiptActivity extends AppCompatActivity {
|
|||||||
try {
|
try {
|
||||||
Log.d("ReceiptActivity", "🔍 Async search for real acquirer: " + referenceId);
|
Log.d("ReceiptActivity", "🔍 Async search for real acquirer: " + referenceId);
|
||||||
|
|
||||||
String queryUrl = "https://be-edc.msvc.app/api-logs?limit=100&sortOrder=DESC&sortColumn=created_at";
|
String queryUrl = "https://be-edc.msvc.app/api-logs?limit=200&sortOrder=DESC&sortColumn=created_at";
|
||||||
|
|
||||||
URL url = new URL(queryUrl);
|
URL url = new URL(queryUrl);
|
||||||
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
|
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
|
||||||
conn.setRequestMethod("GET");
|
conn.setRequestMethod("GET");
|
||||||
conn.setRequestProperty("Accept", "application/json");
|
conn.setRequestProperty("Accept", "application/json");
|
||||||
conn.setRequestProperty("User-Agent", "BDKIPOCApp/1.0");
|
conn.setRequestProperty("User-Agent", "BDKIPOCApp/1.0");
|
||||||
conn.setConnectTimeout(10000);
|
conn.setConnectTimeout(15000);
|
||||||
conn.setReadTimeout(10000);
|
conn.setReadTimeout(15000);
|
||||||
|
|
||||||
if (conn.getResponseCode() == 200) {
|
if (conn.getResponseCode() == 200) {
|
||||||
BufferedReader br = new BufferedReader(new InputStreamReader(conn.getInputStream()));
|
BufferedReader br = new BufferedReader(new InputStreamReader(conn.getInputStream()));
|
||||||
@ -492,63 +521,100 @@ public class ReceiptActivity extends AppCompatActivity {
|
|||||||
org.json.JSONArray results = json.optJSONArray("results");
|
org.json.JSONArray results = json.optJSONArray("results");
|
||||||
|
|
||||||
if (results != null && results.length() > 0) {
|
if (results != null && results.length() > 0) {
|
||||||
|
Log.d("ReceiptActivity", "📊 Async analyzing " + results.length() + " webhook logs");
|
||||||
|
|
||||||
String realAcquirer = searchForRealAcquirer(results, referenceId);
|
String realAcquirer = searchForRealAcquirer(results, referenceId);
|
||||||
|
|
||||||
if (realAcquirer != null && !realAcquirer.isEmpty() && !realAcquirer.equalsIgnoreCase("qris")) {
|
if (realAcquirer != null && !realAcquirer.isEmpty() && !realAcquirer.equalsIgnoreCase("qris")) {
|
||||||
Log.d("ReceiptActivity", "✅ Async found real acquirer: " + realAcquirer + " for reference: " + referenceId);
|
Log.d("ReceiptActivity", "✅ Async found real acquirer: " + realAcquirer);
|
||||||
|
|
||||||
// Update UI on main thread
|
// Update UI on main thread
|
||||||
final String displayAcquirer = getCardTypeFromAcquirer(realAcquirer, null, null);
|
final String displayAcquirer = getCardTypeFromAcquirer(realAcquirer, null, null);
|
||||||
runOnUiThread(() -> {
|
runOnUiThread(() -> {
|
||||||
if (cardType != null) {
|
if (cardType != null) {
|
||||||
cardType.setText(displayAcquirer);
|
cardType.setText(displayAcquirer);
|
||||||
Log.d("ReceiptActivity", "🎨 Updated card type from QRIS to: " + displayAcquirer);
|
Log.d("ReceiptActivity", "🎨 UI UPDATED: QRIS -> " + displayAcquirer);
|
||||||
|
|
||||||
|
// Show a subtle indication that the data was updated
|
||||||
|
showToast("Card type updated: " + displayAcquirer);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
Log.w("ReceiptActivity", "⚠️ Could not determine real acquirer for: " + referenceId);
|
Log.w("ReceiptActivity", "⚠️ Async search found no valid acquirer for: " + referenceId);
|
||||||
// Keep showing "QRIS" instead of defaulting to GoPay
|
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
Log.w("ReceiptActivity", "⚠️ Async search returned no results");
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
Log.w("ReceiptActivity", "⚠️ API call failed with code: " + conn.getResponseCode());
|
Log.w("ReceiptActivity", "⚠️ Async API call failed with code: " + conn.getResponseCode());
|
||||||
}
|
}
|
||||||
|
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
Log.e("ReceiptActivity", "❌ Error fetching real acquirer: " + e.getMessage(), e);
|
Log.e("ReceiptActivity", "❌ Async acquirer fetch error: " + e.getMessage(), e);
|
||||||
}
|
}
|
||||||
}).start();
|
}).start();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* ✅ NEW METHOD: Advanced search for real acquirer in webhook logs
|
|
||||||
*/
|
|
||||||
private String searchForRealAcquirer(org.json.JSONArray results, String referenceId) {
|
private String searchForRealAcquirer(org.json.JSONArray results, String referenceId) {
|
||||||
try {
|
try {
|
||||||
Log.d("ReceiptActivity", "🔍 Analyzing " + results.length() + " webhook logs for acquirer");
|
Log.d("ReceiptActivity", "🔍 Analyzing " + results.length() + " webhook logs for acquirer");
|
||||||
|
Log.d("ReceiptActivity", "🎯 Target reference ID: " + referenceId);
|
||||||
|
|
||||||
|
// Get order_id from intent for additional matching
|
||||||
|
String orderId = getIntent().getStringExtra("order_id");
|
||||||
|
Log.d("ReceiptActivity", "🎯 Target order ID: " + orderId);
|
||||||
|
|
||||||
// Strategy 1: Look for settlement/success transactions first (highest priority)
|
// Strategy 1: Look for settlement/success transactions first (highest priority)
|
||||||
|
Log.d("ReceiptActivity", "🔍 Strategy 1: Searching for settlement/success status");
|
||||||
String acquirerFromSettlement = searchLogsByStatus(results, referenceId, new String[]{"settlement", "capture", "success"});
|
String acquirerFromSettlement = searchLogsByStatus(results, referenceId, new String[]{"settlement", "capture", "success"});
|
||||||
if (acquirerFromSettlement != null) {
|
if (acquirerFromSettlement != null) {
|
||||||
Log.d("ReceiptActivity", "🎯 Found acquirer from settlement: " + acquirerFromSettlement);
|
Log.d("ReceiptActivity", "🎯 SUCCESS: Found acquirer from settlement: " + acquirerFromSettlement);
|
||||||
return acquirerFromSettlement;
|
return acquirerFromSettlement;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Strategy 2: Look for pending transactions
|
// Strategy 2: Look for pending transactions
|
||||||
|
Log.d("ReceiptActivity", "🔍 Strategy 2: Searching for pending status");
|
||||||
String acquirerFromPending = searchLogsByStatus(results, referenceId, new String[]{"pending"});
|
String acquirerFromPending = searchLogsByStatus(results, referenceId, new String[]{"pending"});
|
||||||
if (acquirerFromPending != null) {
|
if (acquirerFromPending != null) {
|
||||||
Log.d("ReceiptActivity", "🎯 Found acquirer from pending: " + acquirerFromPending);
|
Log.d("ReceiptActivity", "🎯 SUCCESS: Found acquirer from pending: " + acquirerFromPending);
|
||||||
return acquirerFromPending;
|
return acquirerFromPending;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Strategy 3: Look for any transaction with this reference
|
// Strategy 3: Look for any transaction with this reference (broadest search)
|
||||||
|
Log.d("ReceiptActivity", "🔍 Strategy 3: Searching for any status");
|
||||||
String acquirerFromAny = searchLogsByStatus(results, referenceId, new String[]{});
|
String acquirerFromAny = searchLogsByStatus(results, referenceId, new String[]{});
|
||||||
if (acquirerFromAny != null) {
|
if (acquirerFromAny != null) {
|
||||||
Log.d("ReceiptActivity", "🎯 Found acquirer from any status: " + acquirerFromAny);
|
Log.d("ReceiptActivity", "🎯 SUCCESS: Found acquirer from any status: " + acquirerFromAny);
|
||||||
return acquirerFromAny;
|
return acquirerFromAny;
|
||||||
}
|
}
|
||||||
|
|
||||||
Log.w("ReceiptActivity", "❌ No acquirer found in webhook logs for: " + referenceId);
|
Log.w("ReceiptActivity", "❌ FAILED: No acquirer found in webhook logs for reference: " + referenceId);
|
||||||
|
|
||||||
|
// Strategy 4: Debug logging - show what we actually found
|
||||||
|
Log.d("ReceiptActivity", "🔍 DEBUG: Showing first 5 log entries for analysis:");
|
||||||
|
for (int i = 0; i < Math.min(5, results.length()); i++) {
|
||||||
|
try {
|
||||||
|
org.json.JSONObject log = results.getJSONObject(i);
|
||||||
|
org.json.JSONObject reqBody = log.optJSONObject("request_body");
|
||||||
|
if (reqBody != null) {
|
||||||
|
String logOrderId = reqBody.optString("order_id", "");
|
||||||
|
String logRefId = reqBody.optString("reference_id", "");
|
||||||
|
String logStatus = reqBody.optString("transaction_status", "");
|
||||||
|
String logAcquirer = reqBody.optString("acquirer", "");
|
||||||
|
String logIssuer = reqBody.optString("issuer", "");
|
||||||
|
|
||||||
|
Log.d("ReceiptActivity", " Log " + (i+1) + ": " +
|
||||||
|
"order_id=" + logOrderId +
|
||||||
|
", ref_id=" + logRefId +
|
||||||
|
", status=" + logStatus +
|
||||||
|
", acquirer=" + logAcquirer +
|
||||||
|
", issuer=" + logIssuer);
|
||||||
|
}
|
||||||
|
} catch (Exception e) {
|
||||||
|
Log.w("ReceiptActivity", "Error parsing debug log " + i + ": " + e.getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return null;
|
return null;
|
||||||
|
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
@ -557,9 +623,6 @@ public class ReceiptActivity extends AppCompatActivity {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* ✅ HELPER METHOD: Search logs by specific status
|
|
||||||
*/
|
|
||||||
private String searchLogsByStatus(org.json.JSONArray results, String referenceId, String[] targetStatuses) {
|
private String searchLogsByStatus(org.json.JSONArray results, String referenceId, String[] targetStatuses) {
|
||||||
try {
|
try {
|
||||||
for (int i = 0; i < results.length(); i++) {
|
for (int i = 0; i < results.length(); i++) {
|
||||||
@ -571,10 +634,24 @@ public class ReceiptActivity extends AppCompatActivity {
|
|||||||
String logTransactionStatus = reqBody.optString("transaction_status", "");
|
String logTransactionStatus = reqBody.optString("transaction_status", "");
|
||||||
String logAcquirer = reqBody.optString("acquirer", "");
|
String logAcquirer = reqBody.optString("acquirer", "");
|
||||||
String logIssuer = reqBody.optString("issuer", "");
|
String logIssuer = reqBody.optString("issuer", "");
|
||||||
|
String logOrderId = reqBody.optString("order_id", "");
|
||||||
|
|
||||||
|
Log.d("ReceiptActivity", "🔍 Checking log: order_id=" + logOrderId +
|
||||||
|
", status=" + logTransactionStatus +
|
||||||
|
", acquirer=" + logAcquirer +
|
||||||
|
", issuer=" + logIssuer);
|
||||||
|
|
||||||
// Check for direct reference match
|
// Check for direct reference match
|
||||||
boolean isDirectMatch = referenceId.equals(logReferenceId);
|
boolean isDirectMatch = referenceId.equals(logReferenceId);
|
||||||
|
|
||||||
|
// ✅ IMPROVED: Also check order_id match from QrisResultActivity
|
||||||
|
boolean isOrderMatch = false;
|
||||||
|
String orderId = getIntent().getStringExtra("order_id");
|
||||||
|
if (orderId != null && !orderId.isEmpty() && orderId.equals(logOrderId)) {
|
||||||
|
isOrderMatch = true;
|
||||||
|
Log.d("ReceiptActivity", "✅ Found order_id match: " + orderId);
|
||||||
|
}
|
||||||
|
|
||||||
// Check custom_field1 for refresh tracking
|
// Check custom_field1 for refresh tracking
|
||||||
boolean isRefreshMatch = false;
|
boolean isRefreshMatch = false;
|
||||||
String customField1 = reqBody.optString("custom_field1", "");
|
String customField1 = reqBody.optString("custom_field1", "");
|
||||||
@ -592,7 +669,13 @@ public class ReceiptActivity extends AppCompatActivity {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Check if this log matches our reference
|
// Check if this log matches our reference
|
||||||
if (isDirectMatch || isRefreshMatch) {
|
if (isDirectMatch || isRefreshMatch || isOrderMatch) {
|
||||||
|
Log.d("ReceiptActivity", "🎯 TRANSACTION MATCH FOUND!");
|
||||||
|
Log.d("ReceiptActivity", " Match type: " +
|
||||||
|
(isDirectMatch ? "DIRECT " : "") +
|
||||||
|
(isRefreshMatch ? "REFRESH " : "") +
|
||||||
|
(isOrderMatch ? "ORDER" : ""));
|
||||||
|
|
||||||
// If target statuses specified, check status
|
// If target statuses specified, check status
|
||||||
if (targetStatuses.length > 0) {
|
if (targetStatuses.length > 0) {
|
||||||
boolean statusMatches = false;
|
boolean statusMatches = false;
|
||||||
@ -602,14 +685,47 @@ public class ReceiptActivity extends AppCompatActivity {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (!statusMatches) continue; // Skip if status doesn't match
|
if (!statusMatches) {
|
||||||
|
Log.d("ReceiptActivity", " Status doesn't match target: " + logTransactionStatus);
|
||||||
|
continue; // Skip if status doesn't match
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Extract acquirer (prefer acquirer field over issuer)
|
// ✅ CRITICAL FIX: For QRIS transactions, prioritize issuer over acquirer
|
||||||
String foundAcquirer = !logAcquirer.isEmpty() ? logAcquirer : logIssuer;
|
String foundAcquirer = null;
|
||||||
if (!foundAcquirer.isEmpty() && !foundAcquirer.equalsIgnoreCase("qris")) {
|
|
||||||
Log.d("ReceiptActivity", "📋 Found acquirer: " + foundAcquirer + " (status: " + logTransactionStatus + ")");
|
// Check if this is a QRIS transaction by payment_type
|
||||||
|
String paymentType = reqBody.optString("payment_type", "");
|
||||||
|
boolean isQrisTransaction = "qris".equalsIgnoreCase(paymentType);
|
||||||
|
|
||||||
|
if (isQrisTransaction) {
|
||||||
|
// For QRIS: issuer contains the actual payment provider (LinkAja, DANA, etc.)
|
||||||
|
// acquirer is usually just "gopay" (the QRIS aggregator)
|
||||||
|
if (!logIssuer.isEmpty() && !logIssuer.equalsIgnoreCase("qris")) {
|
||||||
|
foundAcquirer = logIssuer;
|
||||||
|
Log.d("ReceiptActivity", "📱 QRIS: Using issuer as acquirer: " + foundAcquirer);
|
||||||
|
} else if (!logAcquirer.isEmpty() && !logAcquirer.equalsIgnoreCase("qris")) {
|
||||||
|
foundAcquirer = logAcquirer;
|
||||||
|
Log.d("ReceiptActivity", "📱 QRIS: Fallback to acquirer: " + foundAcquirer);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// For non-QRIS: prefer acquirer over issuer (traditional behavior)
|
||||||
|
if (!logAcquirer.isEmpty() && !logAcquirer.equalsIgnoreCase("qris")) {
|
||||||
|
foundAcquirer = logAcquirer;
|
||||||
|
Log.d("ReceiptActivity", "💳 Non-QRIS: Using acquirer: " + foundAcquirer);
|
||||||
|
} else if (!logIssuer.isEmpty() && !logIssuer.equalsIgnoreCase("qris")) {
|
||||||
|
foundAcquirer = logIssuer;
|
||||||
|
Log.d("ReceiptActivity", "💳 Non-QRIS: Fallback to issuer: " + foundAcquirer);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (foundAcquirer != null && !foundAcquirer.isEmpty()) {
|
||||||
|
Log.d("ReceiptActivity", "✅ FINAL ACQUIRER FOUND: " + foundAcquirer +
|
||||||
|
" (status: " + logTransactionStatus +
|
||||||
|
", payment_type: " + paymentType + ")");
|
||||||
return foundAcquirer;
|
return foundAcquirer;
|
||||||
|
} else {
|
||||||
|
Log.w("ReceiptActivity", "⚠️ Transaction matched but no valid acquirer found");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -626,7 +742,18 @@ public class ReceiptActivity extends AppCompatActivity {
|
|||||||
if (input == null || input.isEmpty()) {
|
if (input == null || input.isEmpty()) {
|
||||||
return input;
|
return input;
|
||||||
}
|
}
|
||||||
return input.substring(0, 1).toUpperCase() + input.substring(1).toLowerCase();
|
|
||||||
|
// Handle special cases
|
||||||
|
String cleaned = input.trim();
|
||||||
|
|
||||||
|
// Special handling for common patterns
|
||||||
|
if (cleaned.toLowerCase().contains("pay")) {
|
||||||
|
// Keep "Pay" capitalized in payment methods
|
||||||
|
return cleaned.substring(0, 1).toUpperCase() + cleaned.substring(1).toLowerCase()
|
||||||
|
.replace("pay", "Pay");
|
||||||
|
}
|
||||||
|
|
||||||
|
return cleaned.substring(0, 1).toUpperCase() + cleaned.substring(1).toLowerCase();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void setAmountData(String amount, String grossAmount) {
|
private void setAmountData(String amount, String grossAmount) {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user