From b2442ada483bb347f3f8f8797d4fa12a1efa3f32 Mon Sep 17 00:00:00 2001 From: riz081 Date: Mon, 30 Jun 2025 21:43:06 +0700 Subject: [PATCH] Implement ReceiptActivity dengan printer --- .../com/example/bdkipoc/ReceiptActivity.java | 258 ++++++++++++++---- 1 file changed, 202 insertions(+), 56 deletions(-) diff --git a/app/src/main/java/com/example/bdkipoc/ReceiptActivity.java b/app/src/main/java/com/example/bdkipoc/ReceiptActivity.java index 9213967..4e56b95 100644 --- a/app/src/main/java/com/example/bdkipoc/ReceiptActivity.java +++ b/app/src/main/java/com/example/bdkipoc/ReceiptActivity.java @@ -1,9 +1,12 @@ package com.example.bdkipoc; import android.content.Intent; +import android.graphics.Bitmap; +import android.graphics.Canvas; import android.graphics.Color; import android.os.Build; import android.os.Bundle; +import android.os.RemoteException; import android.text.TextUtils; import android.util.Log; import android.view.View; @@ -13,7 +16,13 @@ import android.widget.Button; import android.widget.ImageView; import android.widget.LinearLayout; import android.widget.TextView; +import android.widget.Toast; + import androidx.appcompat.app.AppCompatActivity; +import androidx.cardview.widget.CardView; + +import com.sunmi.peripheral.printer.InnerResultCallback; + import java.text.SimpleDateFormat; import java.util.Date; import java.util.Locale; @@ -29,32 +38,6 @@ import java.util.Map; import com.example.bdkipoc.cetakulang.ReprintActivity; public class ReceiptActivity extends AppCompatActivity { - - // Views - private LinearLayout backNavigation; - private ImageView backArrow; - private TextView toolbarTitle; - - // Receipt details - private TextView merchantName; - private TextView merchantLocation; - private TextView midText; - private TextView tidText; - private TextView transactionNumber; - private TextView transactionDate; - private TextView paymentMethod; - private TextView cardType; - private TextView transactionTotal; - private TextView taxPercentage; - private TextView serviceFee; - private TextView finalTotal; - - // Action buttons - private LinearLayout printButton; - private LinearLayout emailButton; - private Button finishButton; - - // ✅ ENHANCED: Mapping dari technical issuer ke display name private static final Map ISSUER_DISPLAY_MAP = new HashMap() {{ put("airpay shopee", "ShopeePay"); put("shopeepay", "ShopeePay"); @@ -76,6 +59,61 @@ public class ReceiptActivity extends AppCompatActivity { put("qris", "QRIS"); }}; + // Views + private LinearLayout backNavigation; + private ImageView backArrow; + private TextView toolbarTitle; + private CardView receiptCard; + + // Receipt details + private TextView merchantName; + private TextView merchantLocation; + private TextView midText; + private TextView tidText; + private TextView transactionNumber; + private TextView transactionDate; + private TextView paymentMethod; + private TextView cardType; + private TextView transactionTotal; + private TextView taxPercentage; + private TextView serviceFee; + private TextView finalTotal; + + // Action buttons + private LinearLayout printButton; + private LinearLayout emailButton; + private Button finishButton; + + // Printer callback + private final InnerResultCallback printCallback = new InnerResultCallback() { + @Override + public void onRunResult(boolean isSuccess) throws RemoteException { + runOnUiThread(() -> { + if (isSuccess) { + showToast("Struk berhasil dicetak"); + } else { + showToast("Gagal mencetak struk"); + } + }); + } + + @Override + public void onReturnString(String result) throws RemoteException { + Log.d("ReceiptActivity", "Print result: " + result); + } + + @Override + public void onRaiseException(int code, String msg) throws RemoteException { + runOnUiThread(() -> showToast("Printer error: " + msg)); + Log.e("ReceiptActivity", "Printer exception: " + code + " - " + msg); + } + + @Override + public void onPrintResult(int code, String msg) throws RemoteException { + Log.d("ReceiptActivity", "Print result code: " + code + ", msg: " + msg); + } + }; + @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); @@ -90,26 +128,15 @@ public class ReceiptActivity extends AppCompatActivity { loadTransactionData(); } - private void setStatusBarColor() { - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { - Window window = getWindow(); - window.addFlags(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS); - window.setStatusBarColor(Color.parseColor("#E31937")); // Red color - - // Make status bar icons white (for dark red background) - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { - View decorView = window.getDecorView(); - decorView.setSystemUiVisibility(0); // Clear light status bar flag - } - } - } - private void initializeViews() { // Navigation backNavigation = findViewById(R.id.back_navigation); backArrow = findViewById(R.id.backArrow); toolbarTitle = findViewById(R.id.toolbarTitle); + // Receipt card view that will be printed + receiptCard = findViewById(R.id.receipt_card); + // Receipt details merchantName = findViewById(R.id.merchant_name); merchantLocation = findViewById(R.id.merchant_location); @@ -130,6 +157,129 @@ public class ReceiptActivity extends AppCompatActivity { finishButton = findViewById(R.id.finish_button); } + private void handlePrintReceipt() { + try { + // Check if printer service is available + if (MyApplication.app.sunmiPrinterService == null) { + showToast("Printer tidak tersedia"); + return; + } + + // Get all the data from the views + String merchantNameText = merchantName.getText().toString(); + String merchantLocationText = merchantLocation.getText().toString(); + String midTextValue = midText.getText().toString(); + String tidTextValue = tidText.getText().toString(); + String transactionNumberText = transactionNumber.getText().toString(); + String transactionDateText = transactionDate.getText().toString(); + String paymentMethodText = paymentMethod.getText().toString(); + String cardTypeText = cardType.getText().toString(); + String transactionTotalText = transactionTotal.getText().toString(); + String taxPercentageText = taxPercentage.getText().toString(); + String serviceFeeText = serviceFee.getText().toString(); + String finalTotalText = finalTotal.getText().toString(); + + showToast("Mencetak struk..."); + + try { + // Start printing + MyApplication.app.sunmiPrinterService.enterPrinterBuffer(true); + + // Set alignment to center + MyApplication.app.sunmiPrinterService.setAlignment(1, null); + + // Print header + MyApplication.app.sunmiPrinterService.printText("# Payvora PRO\n\n", null); + + // Set alignment to left + MyApplication.app.sunmiPrinterService.setAlignment(0, null); + + // Print merchant info + MyApplication.app.sunmiPrinterService.printText(merchantNameText + "\n", null); + MyApplication.app.sunmiPrinterService.printText(merchantLocationText + "\n\n", null); + + // Print MID/TID + MyApplication.app.sunmiPrinterService.printText(midTextValue + " | " + tidTextValue + "\n\n", null); + + // Print transaction details + MyApplication.app.sunmiPrinterService.printText("Nomor transaksi " + transactionNumberText + "\n", null); + MyApplication.app.sunmiPrinterService.printText("Tanggal transaksi " + transactionDateText + "\n", null); + MyApplication.app.sunmiPrinterService.printText("Metode pembayaran " + paymentMethodText + "\n", null); + MyApplication.app.sunmiPrinterService.printText("Jenis Kartu " + cardTypeText + "\n\n", null); + + // Print amounts + MyApplication.app.sunmiPrinterService.printText("Total transaksi " + transactionTotalText + "\n", null); + MyApplication.app.sunmiPrinterService.printText("Pajak (%) " + taxPercentageText + "\n", null); + MyApplication.app.sunmiPrinterService.printText("Biaya Layanan " + serviceFeeText + "\n\n", null); + + // Print total in bold + MyApplication.app.sunmiPrinterService.printText("**TOTAL** **" + finalTotalText + "**\n", null); + + // Add some line feeds + MyApplication.app.sunmiPrinterService.lineWrap(4, null); + + // Exit buffer mode + MyApplication.app.sunmiPrinterService.exitPrinterBuffer(true); + + } catch (RemoteException e) { + e.printStackTrace(); + showToast("Error printer: " + e.getMessage()); + } + + } catch (Exception e) { + Log.e("ReceiptActivity", "Print error", e); + showToast("Error saat mencetak: " + e.getMessage()); + } + } + + private void setStatusBarColor() { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { + Window window = getWindow(); + window.addFlags(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS); + window.setStatusBarColor(Color.parseColor("#E31937")); // Red color + + // Make status bar icons white (for dark red background) + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { + View decorView = window.getDecorView(); + decorView.setSystemUiVisibility(0); // Clear light status bar flag + } + } + } + + /** Create Bitmap from View */ + private Bitmap createBitmapFromView(View view) { + try { + // Enable drawing cache + view.setDrawingCacheEnabled(true); + view.setDrawingCacheQuality(View.DRAWING_CACHE_QUALITY_HIGH); + + // Measure and layout the view to ensure it has correct dimensions + view.measure( + View.MeasureSpec.makeMeasureSpec(view.getWidth(), View.MeasureSpec.EXACTLY), + View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED) + ); + + view.layout(0, 0, view.getMeasuredWidth(), view.getMeasuredHeight()); + + // Create bitmap + Bitmap bitmap = Bitmap.createBitmap( + view.getWidth(), + view.getHeight(), + Bitmap.Config.ARGB_8888 + ); + + Canvas canvas = new Canvas(bitmap); + view.draw(canvas); + + return bitmap; + } catch (Exception e) { + Log.e("ReceiptActivity", "Error creating bitmap", e); + return null; + } finally { + view.setDrawingCacheEnabled(false); + } + } + private void setupClickListeners() { // Back navigation - Goes back to previous activity backNavigation.setOnClickListener(v -> handleBackNavigation()); @@ -279,20 +429,17 @@ public class ReceiptActivity extends AppCompatActivity { return getCurrentDateTime(); } - /** - * Format date specifically for EMV transactions - */ private String formatDateForEmvTransaction(String dateString) { try { // EMV transactions might use different date formats String[] inputFormats = { "dd MMMM yyyy HH:mm", "yyyy-MM-dd HH:mm:ss", - "yyyy-MM-dd'T'HH:mm:ss'Z'", + "yyyy-MM-dd'T'HH:mm:ss.SSS'Z'", "dd/MM/yyyy HH:mm" }; - SimpleDateFormat outputFormat = new SimpleDateFormat("dd MMMM yyyy HH:mm", new Locale("id", "ID")); + SimpleDateFormat outputFormat = new SimpleDateFormat("dd/MM/yy HH:mm:ss", new Locale("id", "ID")); for (String format : inputFormats) { try { @@ -319,11 +466,16 @@ public class ReceiptActivity extends AppCompatActivity { private String formatDateFromCreatedAt(String createdAt) { try { - // Input format from database: "yyyy-MM-dd HH:mm:ss" - SimpleDateFormat inputFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss", Locale.getDefault()); + // Input format from database: "yyyy-MM-dd HH:mm:ss" atau "yyyy-MM-dd'T'HH:mm:ss.SSS'Z'" + SimpleDateFormat inputFormat; + if (createdAt.contains("T")) { + inputFormat = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'", Locale.getDefault()); + } else { + inputFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss", Locale.getDefault()); + } - // Output format for receipt: "dd/MM/yyyy HH:mm" - SimpleDateFormat outputFormat = new SimpleDateFormat("dd MMMM yyyy HH:mm", new Locale("id", "ID")); + // Output format for receipt: "dd/MM/yy HH:mm:ss" + SimpleDateFormat outputFormat = new SimpleDateFormat("dd/MM/yy HH:mm:ss", new Locale("id", "ID")); Date date = inputFormat.parse(createdAt); String formatted = outputFormat.format(date); @@ -333,7 +485,7 @@ public class ReceiptActivity extends AppCompatActivity { } catch (Exception e) { Log.e("ReceiptActivity", "Error formatting date: " + createdAt, e); - // Fallback: try alternative formats or return as-is + // Fallback: return original string if parsing fails return createdAt; } } @@ -1224,12 +1376,6 @@ public class ReceiptActivity extends AppCompatActivity { return sdf.format(new Date()); } - private void handlePrintReceipt() { - // Handle print receipt action - // In real app, this would integrate with printer - showToast("Mencetak struk..."); - } - private void handleEmailReceipt() { // Handle email receipt action // In real app, this would open email intent