39 private RadioGroup radioGroupPaymentMethod;
40 private RadioButton radioButtonMercadoPago, radioButtonCreditCard, radioButtonPaypal;
41 private Button buttonPayNow, buttonRetry;
42 private ProgressBar progressBar;
43 private WebView webViewPayment;
44 private View paymentLayout, webViewLayout, errorLayout;
45 private TextView textViewError;
46 private static final String TAG =
"PaymentFragment";
49 private String currentPaymentRequestId;
52 private static final int ERROR_TIMEOUT = -8;
53 private static final int ERROR_HOST_LOOKUP = -2;
54 private static final int ERROR_CONNECT = -6;
55 private static final int ERROR_IO = -7;
58 private static final int PAGE_LOAD_TIMEOUT = 20000;
59 private Runnable timeoutRunnable;
60 private Handler timeoutHandler =
new Handler();
64 private boolean isNetworkAvailable =
true;
70 public View
onCreateView(LayoutInflater inflater, ViewGroup container,
71 Bundle savedInstanceState) {
73 View view = inflater.inflate(R.layout.fragment_payment, container,
false);
83 radioGroupPaymentMethod = view.findViewById(R.id.radioGroupPaymentMethod);
84 radioButtonCreditCard = view.findViewById(R.id.radioButton4);
85 radioButtonMercadoPago = view.findViewById(R.id.radioButton6);
86 radioButtonPaypal = view.findViewById(R.id.radioButtonPaypal);
87 buttonPayNow = view.findViewById(R.id.button2);
88 buttonRetry = view.findViewById(R.id.buttonRetry);
89 progressBar = view.findViewById(R.id.progressBarPayment);
90 webViewPayment = view.findViewById(R.id.webViewPayment);
91 paymentLayout = view.findViewById(R.id.paymentLayout);
92 webViewLayout = view.findViewById(R.id.webViewLayout);
93 errorLayout = view.findViewById(R.id.errorLayout);
94 textViewError = view.findViewById(R.id.textViewError);
96 radioButtonMercadoPago.setText(
"MercadoPago");
98 radioButtonPaypal.setText(
"PayPal");
101 WebSettings webSettings = webViewPayment.getSettings();
102 webSettings.setJavaScriptEnabled(
true);
103 webSettings.setDomStorageEnabled(
true);
104 webSettings.setCacheMode(WebSettings.LOAD_NO_CACHE);
105 webSettings.setJavaScriptCanOpenWindowsAutomatically(
true);
106 webSettings.setSupportMultipleWindows(
true);
107 webSettings.setLoadWithOverviewMode(
true);
108 webSettings.setUseWideViewPort(
true);
109 webSettings.setSupportZoom(
false);
111 webViewPayment.setWebViewClient(
new WebViewClient() {
113 public boolean shouldOverrideUrlLoading(WebView view, WebResourceRequest request) {
114 String url = request.getUrl().toString();
115 Log.d(TAG,
"URL cargada: " + url);
119 if (url.contains(
"/exito") || url.contains(
"/success") ||
120 url.contains(
"ispcfood.netlify.app/exito") ||
121 url.contains(
"success=true") ||
122 url.contains(
"status=approved")) {
124 Log.d(TAG,
"Detectada URL de pago exitoso: " + url);
125 handlePaymentSuccess();
127 }
else if (url.contains(
"/error") || url.contains(
"/failure") ||
128 url.contains(
"ispcfood.netlify.app/error") ||
129 url.contains(
"status=rejected")) {
131 Log.d(TAG,
"Detectada URL de pago rechazado: " + url);
132 handlePaymentFailure();
134 }
else if (url.contains(
"/pendiente") || url.contains(
"/pending") ||
135 url.contains(
"ispcfood.netlify.app/pendiente") ||
136 url.contains(
"status=pending") || url.contains(
"status=in_process")) {
138 Log.d(TAG,
"Detectada URL de pago pendiente: " + url);
139 handlePaymentPending();
148 public void onPageStarted(WebView view, String url, Bitmap favicon) {
149 super.onPageStarted(view, url, favicon);
150 showWebViewProgress(
true);
153 startPageLoadingTimeout(view, url);
157 public void onPageFinished(WebView view, String url) {
158 super.onPageFinished(view, url);
159 showWebViewProgress(
false);
162 cancelPageLoadingTimeout();
165 Log.d(TAG,
"Página cargada correctamente: " + url);
169 public void onReceivedError(WebView view,
int errorCode, String description, String failingUrl) {
170 super.onReceivedError(view, errorCode, description, failingUrl);
171 Log.e(TAG,
"WebView error: " + description +
" (código: " + errorCode +
") URL: " + failingUrl);
174 if (failingUrl !=
null && failingUrl.contains(
"mercadopago")) {
176 if (errorCode == ERROR_TIMEOUT || errorCode == ERROR_HOST_LOOKUP ||
177 errorCode == ERROR_CONNECT || errorCode == ERROR_IO) {
180 requireActivity().runOnUiThread(
new Runnable() {
183 showWebViewProgress(
false);
184 showErrorView(
true,
"Error de conexión con MercadoPago. Por favor verifica tu conexión a Internet e intenta nuevamente.");
187 if (buttonRetry !=
null) {
188 buttonRetry.setText(
"Reintentar conexión");
194 requireActivity().runOnUiThread(
new Runnable() {
197 showWebViewProgress(
false);
198 showErrorView(
true,
"Error al cargar la página de pago de MercadoPago: " + description);
204 Log.w(TAG,
"Error en recurso secundario, continuando carga: " + failingUrl);
208 buttonPayNow.setOnClickListener(
new View.OnClickListener() {
210 public void onClick(View v) {
211 if (radioButtonMercadoPago.isChecked()) {
212 procesarPagoConMercadoPago();
213 }
else if (radioButtonCreditCard.isChecked() || radioButtonPaypal.isChecked()) {
215 confirmarPedidoBackend();
217 Toast.makeText(requireContext(),
"Por favor selecciona un método de pago", Toast.LENGTH_SHORT).show();
223 buttonRetry.setOnClickListener(
new View.OnClickListener() {
225 public void onClick(View v) {
226 showErrorView(
false,
null);
227 procesarPagoConMercadoPago();
232 private void procesarPagoConMercadoPago() {
234 showErrorView(
false,
null);
238 showErrorView(
true,
"No hay conexión a Internet. Por favor, verifica tu conexión e intenta nuevamente.");
243 new Thread(
new Runnable() {
247 final boolean serverReachable = NetworkUtils.checkUrlAvailability(
"https://backmp.onrender.com", 3000);
249 requireActivity().runOnUiThread(
new Runnable() {
252 if (!serverReachable) {
253 Log.w(TAG,
"Servidor aparentemente no alcanzable, pero intentaremos igualmente");
256 Toast.makeText(requireContext(),
"Conectando con el servidor de pagos...", Toast.LENGTH_SHORT).show();
260 continuarProcesoPago();
266 private void continuarProcesoPago() {
268 String userEmail = sessionManager.getUserEmail();
271 if (userEmail ==
null || userEmail.isEmpty() || userEmail.equals(
"usuario@example.com")) {
273 showErrorView(
true,
"Debes tener un email válido en tu perfil para realizar el pago. Inicia sesión nuevamente o completa tu perfil.");
274 Toast.makeText(requireContext(),
"No se puede continuar sin email de usuario", Toast.LENGTH_LONG).show();
278 Log.d(TAG,
"Iniciando proceso de pago con MercadoPago. Email: " + userEmail);
280 Log.d(TAG,
"Token enviado: " + sessionManager.getToken());
282 mercadoPagoService.createPreference(userEmail,
new MercadoPagoService.MercadoPagoCallback() {
284 public void onSuccess(MercadoPagoPreference preference) {
285 Log.d(TAG,
"Preferencia creada exitosamente: " + preference.getPreferenceId());
286 Log.d(TAG,
"URL de pago: " + preference.getInitPoint());
288 if (preference.getInitPoint() == null || preference.getInitPoint().isEmpty()) {
289 requireActivity().runOnUiThread(new Runnable() {
293 showErrorView(true,
"No se pudo obtener la URL de pago. Por favor, intenta nuevamente.");
300 currentPaymentRequestId = preference.getPaymentRequestId();
302 sessionManager.saveLastInitPoint(preference.getInitPoint());
304 requireActivity().runOnUiThread(new Runnable() {
307 Toast.makeText(requireContext(),
"Redirigiendo a MercadoPago...", Toast.LENGTH_SHORT).show();
308 Intent intent = new Intent(Intent.ACTION_VIEW, android.net.Uri.parse(preference.getInitPoint()));
309 startActivity(intent);
316 public void onError(String errorMessage) {
317 Log.e(TAG,
"Error al crear preferencia: " + errorMessage);
318 requireActivity().runOnUiThread(
new Runnable() {
323 if (errorMessage !=
null && (errorMessage.toLowerCase().contains(
"carrito") || errorMessage.toLowerCase().contains(
"empty") || errorMessage.toLowerCase().contains(
"vacío"))) {
324 showErrorView(
true,
"Tu carrito está vacío. Agrega productos antes de intentar pagar.");
325 }
else if (errorMessage !=
null && (errorMessage.contains(
"500") || errorMessage.toLowerCase().contains(
"servidor"))) {
327 new AlertDialog.Builder(requireContext())
328 .setTitle(
"Error en el servidor de pagos")
329 .setMessage(
"Ocurrió un error al crear la preferencia de pago. ¿Quieres intentar abrir el pago en el navegador web?")
330 .setPositiveButton(
"Abrir en navegador",
new DialogInterface.OnClickListener() {
332 public void onClick(DialogInterface dialog, int which) {
334 String lastInitPoint = (currentPaymentRequestId != null) ? sessionManager.getLastInitPoint() : null;
335 if (lastInitPoint != null && !lastInitPoint.isEmpty()) {
336 Intent browserIntent = new Intent(Intent.ACTION_VIEW, android.net.Uri.parse(lastInitPoint));
337 startActivity(browserIntent);
339 Toast.makeText(requireContext(),
"No se pudo obtener la URL de pago.", Toast.LENGTH_LONG).show();
343 .setNegativeButton(
"Cancelar",
null)
345 showErrorView(
true,
"Error al crear el pago: " + errorMessage);
347 showErrorView(
true,
"Error al crear el pago: " + errorMessage);
354 private void handlePaymentSuccess() {
356 Log.d(TAG,
"Pago exitoso! Redirigiendo a pantalla de confirmación");
359 if (currentPaymentRequestId !=
null && !currentPaymentRequestId.isEmpty()) {
361 mercadoPagoService.
confirmOrder(currentPaymentRequestId,
new MercadoPagoService.OrderConfirmCallback() {
363 public void onSuccess(String orderId) {
366 AlertDialog.Builder builder = new AlertDialog.Builder(requireContext());
367 builder.setTitle(
"Pago Exitoso");
368 builder.setMessage(
"Tu pago ha sido procesado correctamente. ¡Gracias por tu compra!");
369 builder.setPositiveButton(
"Continuar", new DialogInterface.OnClickListener() {
371 public void onClick(DialogInterface dialog, int which) {
373 navigateToSuccessFragment();
376 builder.setCancelable(false);
381 public void onError(String errorMessage) {
384 AlertDialog.Builder builder =
new AlertDialog.Builder(requireContext());
385 builder.setTitle(
"Error al confirmar pedido");
386 builder.setMessage(
"El pago fue exitoso, pero hubo un error al confirmar el pedido: " + errorMessage +
"\nPor favor, contacta soporte si no recibes tu pedido.");
387 builder.setPositiveButton(
"Entendido",
new DialogInterface.OnClickListener() {
389 public void onClick(DialogInterface dialog, int which) {
393 builder.setCancelable(
true);
399 AlertDialog.Builder builder =
new AlertDialog.Builder(requireContext());
400 builder.setTitle(
"Pago Exitoso");
401 builder.setMessage(
"Tu pago ha sido procesado, pero no se pudo confirmar el pedido automáticamente. Si no recibes tu pedido, contacta soporte.");
402 builder.setPositiveButton(
"Continuar",
new DialogInterface.OnClickListener() {
404 public void onClick(DialogInterface dialog, int which) {
405 navigateToSuccessFragment();
408 builder.setCancelable(
false);
413 private void handlePaymentFailure() {
417 AlertDialog.Builder builder =
new AlertDialog.Builder(requireContext());
418 builder.setTitle(
"Pago no completado");
419 builder.setMessage(
"Lo sentimos, el pago no pudo ser procesado. Por favor, intenta con otro método de pago o contacta a tu entidad bancaria.");
420 builder.setPositiveButton(
"Entendido",
new DialogInterface.OnClickListener() {
422 public void onClick(DialogInterface dialog, int which) {
426 builder.setNegativeButton(
"Reintentar",
new DialogInterface.OnClickListener() {
428 public void onClick(DialogInterface dialog, int which) {
429 procesarPagoConMercadoPago();
432 builder.setCancelable(
true);
436 private void handlePaymentPending() {
440 AlertDialog.Builder builder =
new AlertDialog.Builder(requireContext());
441 builder.setTitle(
"Pago en Proceso");
442 builder.setMessage(
"Tu pago está siendo procesado. Puede tomar unos minutos. Recibirás una notificación cuando se complete.");
443 builder.setPositiveButton(
"Entendido",
new DialogInterface.OnClickListener() {
445 public void onClick(DialogInterface dialog, int which) {
450 builder.setCancelable(
true); builder.show();
453 private void showLoading(
boolean show) {
454 progressBar.setVisibility(show ? View.VISIBLE : View.GONE);
455 buttonPayNow.setEnabled(!show);
458 private void showWebViewProgress(
boolean show) {
459 View progressBar = getView().findViewById(R.id.progressBarWebView);
460 if (progressBar !=
null) {
461 progressBar.setVisibility(show ? View.VISIBLE : View.GONE);
465 private void showWebView(
boolean show) {
466 webViewLayout.setVisibility(show ? View.VISIBLE : View.GONE);
467 paymentLayout.setVisibility(show ? View.GONE : View.VISIBLE);
468 errorLayout.setVisibility(View.GONE);
472 private void showErrorView(
boolean show, String errorMessage) {
473 if (show && errorMessage !=
null) {
474 textViewError.setText(errorMessage);
476 errorLayout.setVisibility(show ? View.VISIBLE : View.GONE);
477 webViewLayout.setVisibility(show ? View.GONE : webViewLayout.getVisibility());
478 paymentLayout.setVisibility(show ? View.GONE : paymentLayout.getVisibility());
481 private void verifyPaymentStatus(String paymentRequestId) {
482 Log.d(TAG,
"URL de retorno de MercadoPago detectada");
487 handlePaymentSuccess();
490 private void navigateToSuccessFragment() {
492 String selectedPaymentMethod =
"Efectivo";
494 if (radioGroupPaymentMethod !=
null) {
495 int selectedId = radioGroupPaymentMethod.getCheckedRadioButtonId();
496 Log.d(TAG,
"ID del radio button seleccionado: " + selectedId);
499 if (selectedId == R.id.radioButton6) {
500 selectedPaymentMethod =
"mercadopago";
501 Log.d(TAG,
"Método de pago seleccionado: MercadoPago");
504 else if (selectedId == R.id.radioButtonPaypal) {
505 selectedPaymentMethod =
"paypal";
506 Log.d(TAG,
"Método de pago seleccionado: PayPal");
509 else if (selectedId == R.id.radioButton4) {
510 selectedPaymentMethod =
"credit_card";
511 Log.d(TAG,
"Método de pago seleccionado: Tarjeta de crédito");
513 Log.d(TAG,
"No se detectó ningún método de pago específico, usando el valor por defecto: " + selectedPaymentMethod);
516 Log.e(TAG,
"radioGroupPaymentMethod es nulo");
520 if (buttonPayNow !=
null && buttonPayNow.isEnabled()) {
521 if (radioButtonMercadoPago !=
null && radioButtonMercadoPago.isChecked()) {
522 selectedPaymentMethod =
"mercadopago";
523 Log.d(TAG,
"Método de pago confirmado por estado de RadioButton: MercadoPago");
524 }
else if (radioButtonPaypal !=
null && radioButtonPaypal.isChecked()) {
525 selectedPaymentMethod =
"paypal";
526 Log.d(TAG,
"Método de pago confirmado por estado de RadioButton: PayPal");
527 }
else if (radioButtonCreditCard !=
null && radioButtonCreditCard.isChecked()) {
528 selectedPaymentMethod =
"credit_card";
529 Log.d(TAG,
"Método de pago confirmado por estado de RadioButton: Tarjeta de crédito");
534 SuccessFragment successFragment = SuccessFragment.newInstance(currentPaymentRequestId, selectedPaymentMethod);
535 Log.d(TAG,
"Navegando al fragmento de éxito con método de pago: " + selectedPaymentMethod);
537 FragmentManager fragmentManager = getParentFragmentManager();
538 FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
540 fragmentTransaction.setCustomAnimations(
541 R.anim.slide_in_right,
542 R.anim.slide_out_left
544 fragmentTransaction.replace(R.id.fragment_container_view, successFragment);
545 fragmentTransaction.addToBackStack(
null);
546 fragmentTransaction.commit();
553 private void startPageLoadingTimeout(
final WebView webView,
final String url) {
555 cancelPageLoadingTimeout();
558 timeoutRunnable =
new Runnable() {
562 if (webViewLayout.getVisibility() == View.VISIBLE &&
564 getView().findViewById(R.id.progressBarWebView).getVisibility() == View.VISIBLE) {
566 Log.e(TAG,
"Timeout al cargar la página: " + url);
569 webView.stopLoading();
572 showErrorView(
true,
"La página de pago está tardando demasiado en cargar. " +
573 "Por favor, verifica tu conexión a Internet e intenta nuevamente.");
579 timeoutHandler.postDelayed(timeoutRunnable, PAGE_LOAD_TIMEOUT);
585 private void cancelPageLoadingTimeout() {
586 if (timeoutRunnable !=
null) {
587 timeoutHandler.removeCallbacks(timeoutRunnable);
588 timeoutRunnable =
null;
595 if (connectionMonitor !=
null) {
596 connectionMonitor.startMonitoring();
605 cancelPageLoadingTimeout();
608 if (webViewPayment !=
null) {
609 webViewPayment.stopLoading();
613 if (connectionMonitor !=
null) {
614 connectionMonitor.stopMonitoring();
620 super.onDestroyView();
623 if (webViewPayment !=
null) {
624 webViewPayment.destroy();
631 isNetworkAvailable =
true;
634 if (errorLayout !=
null && errorLayout.getVisibility() == View.VISIBLE &&
635 textViewError.getText().toString().contains(
"conexión")) {
637 requireActivity().runOnUiThread(
new Runnable() {
640 Toast.makeText(requireContext(),
"Conexión restablecida", Toast.LENGTH_SHORT).show();
643 if (currentPaymentRequestId !=
null) {
644 showErrorView(
false,
null);
645 procesarPagoConMercadoPago();
652 isNetworkAvailable =
false;
655 if (webViewLayout !=
null && webViewLayout.getVisibility() == View.VISIBLE) {
656 requireActivity().runOnUiThread(
new Runnable() {
659 showWebViewProgress(
false);
660 showErrorView(
true,
"Se ha perdido la conexión a Internet. Por favor, verifica tu conexión y reintenta.");
669 private void confirmarPedidoBackend() {
672 showErrorView(
true,
"No hay conexión a Internet. Por favor, verifica tu conexión e intenta nuevamente.");
675 String url =
"https://backmobile1.onrender.com/appCART/confirmar/";
676 String token = sessionManager.
getToken();
677 Log.d(
"PaymentFragment",
"Token enviado en confirmarPedidoBackend: " + token);
678 if (token ==
null || token.isEmpty()) {
680 showErrorView(
true,
"Debes iniciar sesión para confirmar el pedido.");
683 com.android.volley.RequestQueue queue = com.android.volley.toolbox.Volley.newRequestQueue(requireContext());
684 com.android.volley.toolbox.JsonObjectRequest request =
new com.android.volley.toolbox.JsonObjectRequest(
685 com.android.volley.Request.Method.POST, url,
null,
686 new com.android.volley.Response.Listener<org.json.JSONObject>() {
688 public void onResponse(org.json.JSONObject response) {
690 new android.app.AlertDialog.Builder(requireContext())
691 .setTitle(
"Pedido confirmado")
692 .setMessage(
"Tu pedido ha sido confirmado y el carrito se ha vaciado. ¡Gracias por tu compra!")
693 .setPositiveButton(
"Continuar", new android.content.DialogInterface.OnClickListener() {
695 public void onClick(android.content.DialogInterface dialog, int which) {
696 navigateToSuccessFragment();
699 .setCancelable(false)
703 new com.android.volley.Response.ErrorListener() {
705 public void onErrorResponse(com.android.volley.VolleyError error) {
707 String msg =
"Error al confirmar el pedido";
708 if (error.networkResponse !=
null) {
709 msg +=
" (código: " + error.networkResponse.statusCode +
")";
711 showErrorView(
true, msg);
715 public java.util.Map<String, String> getHeaders() {
716 java.util.Map<String, String> headers =
new java.util.HashMap<>();
717 headers.put(
"Authorization",
"Bearer " + token);
718 Log.d(
"PaymentFragment",
"Header Authorization enviado: Bearer " + token);