From 6660fca373c4f6c71e61e7d20e4271bc2af82289 Mon Sep 17 00:00:00 2001 From: riz081 Date: Sat, 28 Jun 2025 00:03:27 +0700 Subject: [PATCH] Implement PaymentActivity dan ReprintActivity --- .../com/example/bdkipoc/ReceiptActivity.java | 117 ++++++ .../bdkipoc/cetakulang/ReprintActivity.java | 336 +++++++++++++++--- .../cetakulang/ReprintAdapterActivity.java | 135 +++++-- 3 files changed, 508 insertions(+), 80 deletions(-) diff --git a/app/src/main/java/com/example/bdkipoc/ReceiptActivity.java b/app/src/main/java/com/example/bdkipoc/ReceiptActivity.java index b4521ea..9213967 100644 --- a/app/src/main/java/com/example/bdkipoc/ReceiptActivity.java +++ b/app/src/main/java/com/example/bdkipoc/ReceiptActivity.java @@ -343,6 +343,20 @@ public class ReceiptActivity extends AppCompatActivity { */ private String getDisplayPaymentMethod(String channelCode, String fallbackPaymentMethod, boolean isEmvTransaction, boolean emvMode) { + + // ✅ NEW: Check if this is from ReprintActivity + String callingActivity = getIntent().getStringExtra("calling_activity"); + boolean isFromReprintActivity = "ReprintActivity".equals(callingActivity); + + if (isFromReprintActivity) { + // For ReprintActivity, use the payment_method that was already processed + if (fallbackPaymentMethod != null && !fallbackPaymentMethod.isEmpty()) { + Log.d("ReceiptActivity", "✅ REPRINT: Using processed payment method: " + fallbackPaymentMethod); + return fallbackPaymentMethod; + } + } + + // Continue with existing logic for other sources if (isEmvTransaction) { // For EMV transactions, be more specific if (emvMode) { @@ -430,9 +444,20 @@ public class ReceiptActivity extends AppCompatActivity { Log.d("ReceiptActivity", "🔍 ENHANCED CARD TYPE DETECTION:"); Log.d("ReceiptActivity", " Input Card Type: " + cardTypeStr); Log.d("ReceiptActivity", " Input Acquirer: " + acquirer); + Log.d("ReceiptActivity", " Channel Code: " + channelCode); Log.d("ReceiptActivity", " Is EMV Transaction: " + isEmvTransaction); Log.d("ReceiptActivity", " Is QRIS Transaction: " + isQrisTransaction); + // ✅ NEW: Check if this is from ReprintActivity + String callingActivity = getIntent().getStringExtra("calling_activity"); + boolean isFromReprintActivity = "ReprintActivity".equals(callingActivity); + Log.d("ReceiptActivity", " Is from ReprintActivity: " + isFromReprintActivity); + + if (isFromReprintActivity) { + return handleReprintActivityCardType(cardTypeStr, acquirer, channelCode, referenceId); + } + + // Continue with existing logic for other sources if (isEmvTransaction) { // ✅ FOR EMV TRANSACTIONS: Priority to cardTypeStr from ResultTransactionActivity if (cardTypeStr != null && !cardTypeStr.isEmpty() && !cardTypeStr.equalsIgnoreCase("unknown")) { @@ -492,6 +517,98 @@ public class ReceiptActivity extends AppCompatActivity { } } + private String handleReprintActivityCardType(String cardTypeStr, String acquirer, String channelCode, String referenceId) { + Log.d("ReceiptActivity", "🔍 HANDLING REPRINT ACTIVITY CARD TYPE:"); + Log.d("ReceiptActivity", " Provided Card Type: " + cardTypeStr); + Log.d("ReceiptActivity", " Channel Code: " + channelCode); + Log.d("ReceiptActivity", " Acquirer: " + acquirer); + + // Priority 1: If channelCode indicates QRIS, search for real acquirer + if ("QRIS".equalsIgnoreCase(channelCode) || "RETAIL_OUTLET".equalsIgnoreCase(channelCode)) { + Log.d("ReceiptActivity", "🔍 QRIS detected from ReprintActivity"); + + if (referenceId != null && !referenceId.isEmpty()) { + String realAcquirer = fetchRealAcquirerSync(referenceId); + if (realAcquirer != null && !realAcquirer.isEmpty() && !realAcquirer.equalsIgnoreCase("qris")) { + String mappedAcquirer = getCardTypeFromAcquirer(realAcquirer, null, null); + Log.d("ReceiptActivity", "✅ REPRINT QRIS: Found real acquirer: " + realAcquirer + " -> " + mappedAcquirer); + return mappedAcquirer; + } else { + Log.w("ReceiptActivity", "⚠️ REPRINT QRIS: No real acquirer found, using generic QRIS"); + // Start async search for better results + fetchRealAcquirerFromWebhook(referenceId); + return "QRIS"; + } + } else { + return "QRIS"; + } + } + + // Priority 2: Use cardTypeStr if it's meaningful + if (cardTypeStr != null && !cardTypeStr.isEmpty() && + !cardTypeStr.equalsIgnoreCase("unknown") && + !cardTypeStr.equalsIgnoreCase("retail_outlet")) { + Log.d("ReceiptActivity", "✅ REPRINT: Using provided card type: " + cardTypeStr); + return cardTypeStr; + } + + // Priority 3: Map from channelCode + if (channelCode != null && !channelCode.isEmpty()) { + String mappedFromChannel = mapChannelCodeToCardType(channelCode); + Log.d("ReceiptActivity", "✅ REPRINT: Mapped from channel code: " + channelCode + " -> " + mappedFromChannel); + return mappedFromChannel; + } + + // Priority 4: Use acquirer if available + if (acquirer != null && !acquirer.isEmpty() && !acquirer.equalsIgnoreCase("qris")) { + String mappedAcquirer = getCardTypeFromAcquirer(acquirer, channelCode, null); + Log.d("ReceiptActivity", "✅ REPRINT: Using mapped acquirer: " + mappedAcquirer); + return mappedAcquirer; + } + + // Final fallback + Log.w("ReceiptActivity", "⚠️ REPRINT: Using final fallback: Unknown"); + return "Unknown"; + } + + private String mapChannelCodeToCardType(String channelCode) { + if (channelCode == null || channelCode.isEmpty()) { + return "Unknown"; + } + + String code = channelCode.toUpperCase().trim(); + + switch (code) { + case "QRIS": + case "RETAIL_OUTLET": + return "QRIS"; + case "DEBIT": + case "DEBIT_CARD": + return "Visa"; // Default for debit + case "CREDIT": + case "CREDIT_CARD": + return "Mastercard"; // Default for credit + case "BCA": + return "BCA"; + case "MANDIRI": + return "Mandiri"; + case "BNI": + return "BNI"; + case "BRI": + return "BRI"; + case "PERMATA": + return "Permata"; + case "CIMB": + return "CIMB Niaga"; + case "DANAMON": + return "Danamon"; + case "BSI": + return "BSI"; + default: + return capitalizeFirstLetter(channelCode.replace("_", " ")); + } + } + private String getCardTypeFromAcquirer(String acquirer, String channelCode, String fallbackCardType) { // STEP 1: If we have a valid acquirer that's not generic "qris", use it if (acquirer != null && !acquirer.isEmpty() && !acquirer.equalsIgnoreCase("qris")) { diff --git a/app/src/main/java/com/example/bdkipoc/cetakulang/ReprintActivity.java b/app/src/main/java/com/example/bdkipoc/cetakulang/ReprintActivity.java index 38718a6..845cc6f 100644 --- a/app/src/main/java/com/example/bdkipoc/cetakulang/ReprintActivity.java +++ b/app/src/main/java/com/example/bdkipoc/cetakulang/ReprintActivity.java @@ -1001,93 +1001,196 @@ public class ReprintActivity extends AppCompatActivity implements ReprintAdapter // ✅ REST OF THE CLASS: Existing methods remain the same @Override public void onPrintClick(Transaction transaction) { - // Open ReceiptActivity with transaction data + Log.d("ReprintActivity", "=== OPENING RECEIPT FOR TRANSACTION ==="); + Log.d("ReprintActivity", "📋 Transaction details:"); + Log.d("ReprintActivity", " Reference ID: " + transaction.referenceId); + Log.d("ReprintActivity", " Channel Code: " + transaction.channelCode); + Log.d("ReprintActivity", " Channel Category: " + transaction.channelCategory); + Log.d("ReprintActivity", " Amount: " + transaction.amount); + Log.d("ReprintActivity", " Status: " + transaction.status); + + // Open ReceiptActivity with enhanced transaction data Intent intent = new Intent(this, ReceiptActivity.class); // Add calling activity information for proper back navigation intent.putExtra("calling_activity", "ReprintActivity"); - // Extract and send raw amount properly + // ✅ ENHANCED: Extract and send raw amount properly String rawAmount = extractRawAmount(transaction.amount); + Log.d("ReprintActivity", "💰 Amount processing: '" + transaction.amount + "' -> '" + rawAmount + "'"); - Log.d("ReprintActivity", "Opening receipt for transaction: " + transaction.referenceId + - ", channel: " + transaction.channelCode + ", original amount: '" + transaction.amount + "'"); + // ✅ ENHANCED: Get payment method using new improved logic + String displayPaymentMethod = getPaymentMethodName(transaction.channelCode, transaction.channelCategory); + Log.d("ReprintActivity", "💳 Payment method: " + displayPaymentMethod); - // Send transaction data to ReceiptActivity + // ✅ ENHANCED: Determine card type for receipt using improved logic + String cardTypeForReceipt = determineCardTypeForReceipt(transaction.channelCode, transaction.channelCategory, transaction.referenceId); + Log.d("ReprintActivity", "🏷️ Card type for receipt: " + cardTypeForReceipt); + + // ✅ ENHANCED: Get acquirer using improved logic + String acquirer = getRealAcquirerForQris(transaction.referenceId, transaction.channelCode); + Log.d("ReprintActivity", "🎯 Determined acquirer: " + acquirer); + + // Send comprehensive transaction data to ReceiptActivity intent.putExtra("transaction_id", transaction.referenceId); intent.putExtra("reference_id", transaction.referenceId); // Nomor Transaksi intent.putExtra("transaction_amount", rawAmount); // Total transaksi intent.putExtra("gross_amount", rawAmount); // Consistent with transaction_amount intent.putExtra("created_at", transaction.createdAt); // Tanggal transaksi (will be formatted) intent.putExtra("transaction_date", formatDate(transaction.createdAt)); // Backup formatted date - intent.putExtra("payment_method", getPaymentMethodName(transaction.channelCode, transaction.channelCategory)); - intent.putExtra("channel_code", transaction.channelCode); // Metode Pembayaran - intent.putExtra("channel_category", transaction.channelCategory); - intent.putExtra("card_type", transaction.channelCategory); - intent.putExtra("merchant_name", transaction.merchantName); + + // ✅ ENHANCED: Send improved payment method and card type + intent.putExtra("payment_method", displayPaymentMethod); // User-friendly payment method + intent.putExtra("channel_code", transaction.channelCode); // Original channel code for processing + intent.putExtra("channel_category", transaction.channelCategory); // Original category for processing + intent.putExtra("card_type", cardTypeForReceipt); // Enhanced card type for display + + // Merchant information + intent.putExtra("merchant_name", transaction.merchantName != null ? transaction.merchantName : "Marcel Panjaitan"); intent.putExtra("merchant_location", "Jakarta, Indonesia"); + // ✅ ENHANCED: Send acquirer for proper card type detection in ReceiptActivity + intent.putExtra("acquirer", acquirer); + // Add MID and TID (default values since not available in Transaction model) intent.putExtra("mid", "71000026521"); // MID intent.putExtra("tid", "73001500"); // TID - // ✅ ENHANCED: Use improved acquirer determination - String acquirer = getRealAcquirerForQris(transaction.referenceId, transaction.channelCode); - intent.putExtra("acquirer", acquirer); // Jenis Kartu + // ✅ NEW: Add transaction status for receipt processing + intent.putExtra("transaction_status", transaction.status); - Log.d("ReprintActivity", "🎯 Determined acquirer: " + acquirer + " for channel: " + transaction.channelCode); + // ✅ NEW: Add transaction type information + intent.putExtra("transaction_type", transaction.type); + + Log.d("ReprintActivity", "🚀 LAUNCHING RECEIPT ACTIVITY"); + Log.d("ReprintActivity", "📤 Sent data summary:"); + Log.d("ReprintActivity", " Payment Method: " + displayPaymentMethod); + Log.d("ReprintActivity", " Card Type: " + cardTypeForReceipt); + Log.d("ReprintActivity", " Acquirer: " + acquirer); + Log.d("ReprintActivity", " Amount: " + rawAmount); + Log.d("ReprintActivity", "========================================"); startActivity(intent); } - /** - * ✅ ENHANCED: Dynamic acquirer determination instead of defaulting to GoPay - */ - private String determineAcquirerFromChannelCode(String channelCode) { - if (channelCode == null) return "unknown"; // ✅ CHANGED: unknown instead of gopay + private String determineCardTypeForReceipt(String channelCode, String channelCategory, String referenceId) { + Log.d("ReprintActivity", "🔍 Determining card type for receipt:"); + Log.d("ReprintActivity", " channelCode: " + channelCode); + Log.d("ReprintActivity", " channelCategory: " + channelCategory); + Log.d("ReprintActivity", " referenceId: " + referenceId); - switch (channelCode.toLowerCase()) { + // Priority 1: Direct channel code mapping + if (channelCode != null && !channelCode.isEmpty()) { + String code = channelCode.toUpperCase().trim(); + + switch (code) { + case "QRIS": + case "RETAIL_OUTLET": + // For QRIS, return the channel code so ReceiptActivity can detect real acquirer + Log.d("ReprintActivity", "✅ QRIS detected, returning for real acquirer detection"); + return "QRIS"; + case "DEBIT": + case "DEBIT_CARD": + return "Debit"; + case "CREDIT": + case "CREDIT_CARD": + return "Credit"; + case "BCA": + case "MANDIRI": + case "BNI": + case "BRI": + case "PERMATA": + case "CIMB": + case "DANAMON": + case "BSI": + return code; + default: + Log.d("ReprintActivity", "🔍 Unknown channelCode, checking channelCategory"); + break; + } + } + + // Priority 2: Channel category mapping + if (channelCategory != null && !channelCategory.isEmpty()) { + String category = channelCategory.toUpperCase().trim(); + + switch (category) { + case "RETAIL_OUTLET": + return "QRIS"; + case "DEBIT": + case "DEBIT_CARD": + return "Debit"; + case "CREDIT": + case "CREDIT_CARD": + return "Credit"; + case "E_MONEY": + case "EMONEY": + return "E-Money"; + default: + return capitalizeFirstLetter(channelCategory); + } + } + + // Final fallback + Log.w("ReprintActivity", "⚠️ No valid card type found, defaulting to Unknown"); + return "Unknown"; + } + + private String determineAcquirerFromChannelCode(String channelCode) { + if (channelCode == null) return "unknown"; + + String code = channelCode.toLowerCase().trim(); + Log.d("ReprintActivity", "🔍 Determining acquirer from channelCode: " + channelCode); + + switch (code) { case "qris": - // ✅ IMPROVED: For QRIS, try to get real acquirer or return generic - return "qris"; // Will be processed by receipt activity to find real acquirer + case "retail_outlet": + // ✅ For QRIS/RETAIL_OUTLET, return qris to trigger real acquirer detection + Log.d("ReprintActivity", "🔍 QRIS/RETAIL_OUTLET detected, will search for real acquirer"); + return "qris"; case "bca": - return "bca"; + return "BCA"; case "mandiri": - return "mandiri"; + return "Mandiri"; case "bni": - return "bni"; + return "BNI"; case "bri": - return "bri"; + return "BRI"; case "permata": - return "permata"; + return "Permata"; case "cimb": - return "cimb"; + return "CIMB Niaga"; case "danamon": - return "danamon"; + return "Danamon"; case "bsi": - return "bsi"; + return "BSI"; case "debit": - return "visa"; // Default for debit cards + case "debit_card": + return "Visa"; // Default for debit cards case "credit": - return "mastercard"; // Default for credit cards + case "credit_card": + return "Mastercard"; // Default for credit cards default: - return "unknown"; // ✅ CHANGED: unknown instead of gopay for unknown channels + Log.d("ReprintActivity", "🔍 Unknown channelCode: " + channelCode + ", returning as-is"); + return capitalizeFirstLetter(channelCode); } } - /** - * ✅ NEW METHOD: Try to get real acquirer for QRIS transactions from current transaction data - * This method can be enhanced to query webhook API for real acquirer - */ private String getRealAcquirerForQris(String referenceId, String channelCode) { - // If not QRIS, return channel code - if (!"QRIS".equalsIgnoreCase(channelCode)) { - return determineAcquirerFromChannelCode(channelCode); + Log.d("ReprintActivity", "🔍 Getting real acquirer for referenceId: " + referenceId + ", channelCode: " + channelCode); + + // If not QRIS-related, use standard mapping + if (!"QRIS".equalsIgnoreCase(channelCode) && !"RETAIL_OUTLET".equalsIgnoreCase(channelCode)) { + String acquirer = determineAcquirerFromChannelCode(channelCode); + Log.d("ReprintActivity", "🔍 Non-QRIS transaction, mapped to: " + acquirer); + return acquirer; } - // For QRIS, we could implement real-time acquirer lookup here + // For QRIS transactions, try to get real acquirer + Log.d("ReprintActivity", "🔍 QRIS transaction detected, attempting real acquirer lookup"); + + // Try to get from cache first (if implemented) // For now, return "qris" and let ReceiptActivity handle the detection - Log.d("ReprintActivity", "🔍 QRIS transaction detected, deferring acquirer detection to ReceiptActivity"); return "qris"; } @@ -1137,24 +1240,141 @@ public class ReprintActivity extends AppCompatActivity implements ReprintAdapter } private String getPaymentMethodName(String channelCode, String channelCategory) { - if (channelCode == null) return "Unknown"; + Log.d("ReprintActivity", "🔍 Enhanced payment method mapping:"); + Log.d("ReprintActivity", " channelCode: " + channelCode); + Log.d("ReprintActivity", " channelCategory: " + channelCategory); - switch (channelCode.toUpperCase()) { - case "QRIS": return "QRIS"; - case "DEBIT": return "Kartu Debit"; - case "CREDIT": return "Kartu Kredit"; - case "BCA": - case "MANDIRI": - case "BNI": - case "BRI": return "Kartu " + channelCode.toUpperCase(); - case "CASH": return "Tunai"; - case "EDC": return "EDC"; - default: - if (channelCategory != null && !channelCategory.isEmpty()) { - return channelCategory.toUpperCase(); - } - return channelCode.toUpperCase(); + // Priority 1: Use channelCode for specific mapping + if (channelCode != null && !channelCode.isEmpty()) { + String code = channelCode.toUpperCase().trim(); + + switch (code) { + case "QRIS": + Log.d("ReprintActivity", "✅ Mapped to: QRIS"); + return "QRIS"; + case "DEBIT": + case "DEBIT_CARD": + Log.d("ReprintActivity", "✅ Mapped to: Kartu Debit"); + return "Kartu Debit"; + case "CREDIT": + case "CREDIT_CARD": + Log.d("ReprintActivity", "✅ Mapped to: Kartu Kredit"); + return "Kartu Kredit"; + case "BCA": + return "BCA"; + case "MANDIRI": + return "Mandiri"; + case "BNI": + return "BNI"; + case "BRI": + return "BRI"; + case "PERMATA": + return "Permata"; + case "CIMB": + return "CIMB Niaga"; + case "DANAMON": + return "Danamon"; + case "BSI": + return "BSI"; + case "CASH": + return "Tunai"; + case "EDC": + return "EDC"; + case "RETAIL_OUTLET": + // ✅ ENHANCED: For RETAIL_OUTLET, use intelligent detection + String detectedMethod = detectPaymentMethodFromRetailOutlet(channelCategory); + Log.d("ReprintActivity", "🔍 RETAIL_OUTLET detected as: " + detectedMethod); + return detectedMethod; + default: + Log.d("ReprintActivity", "🔍 Unknown channelCode: " + code + ", checking channelCategory"); + break; + } } + + // Priority 2: Use channelCategory as fallback + if (channelCategory != null && !channelCategory.isEmpty()) { + String mappedFromCategory = mapChannelCategoryToPaymentMethod(channelCategory); + Log.d("ReprintActivity", "✅ Mapped from channelCategory: " + mappedFromCategory); + return mappedFromCategory; + } + + // Final fallback + Log.w("ReprintActivity", "⚠️ No valid payment method found, defaulting to Unknown"); + return "Unknown"; + } + + private String detectPaymentMethodFromRetailOutlet(String channelCategory) { + if (channelCategory == null || channelCategory.isEmpty()) { + return "QRIS"; // Most RETAIL_OUTLET are QRIS + } + + String category = channelCategory.toUpperCase().trim(); + + switch (category) { + case "RETAIL_OUTLET": + return "QRIS"; // RETAIL_OUTLET + RETAIL_OUTLET = QRIS + case "DEBIT": + case "DEBIT_CARD": + return "Kartu Debit"; + case "CREDIT": + case "CREDIT_CARD": + return "Kartu Kredit"; + case "E_MONEY": + case "EMONEY": + return "E-Money"; + default: + return "QRIS"; // Default assumption + } + } + + private String mapChannelCategoryToPaymentMethod(String channelCategory) { + if (channelCategory == null || channelCategory.isEmpty()) { + return "Unknown"; + } + + String category = channelCategory.toUpperCase().trim(); + + switch (category) { + case "RETAIL_OUTLET": + return "QRIS"; + case "DEBIT": + case "DEBIT_CARD": + return "Kartu Debit"; + case "CREDIT": + case "CREDIT_CARD": + return "Kartu Kredit"; + case "E_MONEY": + case "EMONEY": + return "E-Money"; + case "BANK_TRANSFER": + return "Transfer Bank"; + case "VIRTUAL_ACCOUNT": + return "Virtual Account"; + case "QRIS": + return "QRIS"; + default: + return capitalizeFirstLetter(channelCategory); + } + } + + private String capitalizeFirstLetter(String text) { + if (text == null || text.isEmpty()) { + return text; + } + + String cleaned = text.trim().replace("_", " "); + String[] words = cleaned.split("\\s+"); + StringBuilder result = new StringBuilder(); + + for (String word : words) { + if (word.length() > 0) { + result.append(Character.toUpperCase(word.charAt(0))) + .append(word.substring(1).toLowerCase()) + .append(" "); + } + } + + return result.toString().trim(); } private String formatDate(String rawDate) { diff --git a/app/src/main/java/com/example/bdkipoc/cetakulang/ReprintAdapterActivity.java b/app/src/main/java/com/example/bdkipoc/cetakulang/ReprintAdapterActivity.java index 205af2d..02ded51 100644 --- a/app/src/main/java/com/example/bdkipoc/cetakulang/ReprintAdapterActivity.java +++ b/app/src/main/java/com/example/bdkipoc/cetakulang/ReprintAdapterActivity.java @@ -528,37 +528,128 @@ public class ReprintAdapterActivity extends RecyclerView.Adapter