Nessun risultato. Prova con un altro termine.
Guide
Notizie
Software
Tutorial

Gestire gli eventi di pagamento con Angular

Angular: integrazione di PayPal e Stripe con gestione pagamenti, invio dei dati al server, risposte delle API e aggiornamento della UI
Angular: integrazione di PayPal e Stripe con gestione pagamenti, invio dei dati al server, risposte delle API e aggiornamento della UI
Link copiato negli appunti

In questa parte della nostra guida ci concentreremo su come completare l'integrazione di PayPal e Stripe nella nostra applicazione Angular. Abbiamo già configurato i componenti necessari per gestire i pagamenti. Ora ci occuperemo di come gestire gli eventi di pagamento, inviare i dati al server, gestire le risposte delle API e aggiornare l'interfaccia utente in base allo stato delle transazioni. Utilizzeremo l'applicazione già creata che include i componenti PayPalPaymentComponent e StripePaymentComponent.

Gestione degli eventi di pagamento

La gestione degli eventi di pagamento è cruciale per monitorare l'intero processo di transazione. I due principali sistemi di pagamento che stiamo utilizzando, PayPal e Stripe, forniscono eventi che possiamo catturare e gestire. Questo ci permette non solo di informare gli utenti riguardo allo stato delle loro transazioni. Consente anche di eseguire operazioni come l'aggiornamento dei dati nel database.

Nei componenti PayPalPaymentComponent e StripePaymentComponent abbiamo già impostato i metodi per iniziare il processo di pagamento. Ora dobbiamo aggiungere la logica per gestire il successo o il fallimento delle transazioni.

Aggiornamento di PayPalPaymentComponent

Aggiungiamo il metodo per inviare i dati del pagamento al server nel nostro PayPalPaymentComponent. Dopo che l'ordine è stato catturato invieremo i dettagli della transazione ad un endpoint del nostro server.

import { Component, OnInit } from '@angular/core';
import { environment } from '../../environments/environments';
import { CommonModule } from '@angular/common';
import { RouterOutlet } from '@angular/router';
import { HttpClient } from '@angular/common/http'; // Rimuovi l'importazione di HttpClientModule
import { tap, catchError } from 'rxjs/operators';
import { of } from 'rxjs'; // Importa 'of' per gestire gli errori
@Component({
  selector: 'app-paypal-payment',
  templateUrl: './pay-pal-payment-component.component.html',
  styleUrls: ['./pay-pal-payment-component.component.css'],
  imports: [CommonModule, RouterOutlet], // Rimuovi HttpClientModule
  standalone: true,
})
export class PayPalPaymentComponent implements OnInit {
  constructor(private http: HttpClient) {}
  onApprove(data: any, actions: any) {
    return actions.order.capture().then((details: any) => {
      alert('Transaction completed by ' + details.payer.name.given_name);
      this.sendPaymentDetails(details);
    });
  }
  sendPaymentDetails(paymentDetails: any) {
    this.http.post('https://your-server.com/api/payments', paymentDetails).pipe(
      tap(response => {
        console.log('Payment details sent to the server:', response);
      }),
      catchError(error => {
        console.error('Error sending payment details:', error);
        return of(null); // Restituisce un valore alternativo in caso di errore
      })
    ).subscribe(); // La sottoscrizione avviene, ma senza callback espliciti
  }
  ngOnInit(): void {
    this.loadPayPalScript();  // Carica lo script di PayPal all'inizio
  }
  loadPayPalScript(): void {
    if (!window.document.getElementById('paypal-script')) {
      const script = window.document.createElement('script');
      script.id = 'paypal-script';
      script.src = `https://www.paypal.com/sdk/js?client-id=${environment.paypalClientId}&currency=USD`;
      script.onload = () => {
        console.log('PayPal script loaded');
        this.renderPayPalButton();
      };
      script.onerror = () => {
        console.error('Error loading PayPal script');
      };
      window.document.body.appendChild(script);
    } else {
      this.renderPayPalButton(); // Chiamalo anche se lo script è già caricato
    }
  }
  renderPayPalButton(): void {
    console.log('Window.paypal:', window.paypal); // Log per verificare l'oggetto
    if (window.paypal) {
      window.paypal.Buttons({
        createOrder: (data: any, actions: any) => {
          return actions.order.create({
            purchase_units: [{
              amount: { value: '25.00' }
            }]
          });
        },
        onApprove: (data: any, actions: any) => {
          return actions.order.capture().then((details: any) => {
            alert('Transaction completed by ' + details.payer.name.given_name);
          });
        }
      }).render('#paypal-button-container');
    } else {
      console.error('PayPal SDK not loaded');
    }
  }
}

Implementazione nei metodi di StripePaymentComponent

Analogamente, nel StripePaymentComponent dobbiamo gestire il pagamento e inviare i dati al server. Aggiungiamo la logica nel metodo makePayment:

import { Component, OnInit } from '@angular/core';
import { environment } from '../../environments/environments';
import { CommonModule } from '@angular/common';
import { RouterOutlet } from '@angular/router';
import { HttpClient } from '@angular/common/http'; // Mantieni HttpClient
import { tap, catchError } from 'rxjs/operators';
import { of } from 'rxjs'; // Importa 'of' per la gestione degli errori
@Component({
  selector: 'app-stripe-payment',
  templateUrl: './stripe-payment-component.component.html',
  styleUrls: ['./stripe-payment-component.component.css'],
  imports: [CommonModule, RouterOutlet], // Rimuovi HttpClientModule
  standalone: true,
})
export class StripePaymentComponent implements OnInit {
  paymentHandler: any = null;
  stripeAPIKey: string = environment.stripeKey;  // Chiave pubblica di Stripe
  constructor(private http: HttpClient) {}
  ngOnInit(): void {
    this.loadStripeScript();  // Carica lo script di Stripe all'inizio
  }
  makePayment(amount: number): void {
    const paymentHandler = (window).StripeCheckout.configure({
      key: this.stripeAPIKey,
      locale: 'auto',
      token: (stripeToken: any) => {
        console.log(stripeToken);
        this.sendStripePaymentDetails(stripeToken);  // Invia il token al server
      },
    });
    paymentHandler.open({
      name: 'Esempio Applicazione Angular',
      description: 'Pagamenti con Stripe',
      amount: amount * 100,  // Importo in centesimi
    });
  }
  sendStripePaymentDetails(token: any) {
    this.http.post('https://your-server.com/api/stripe-payments', token).pipe(
      tap(response => {
        console.log('Stripe payment details sent to the server:', response);
      }),
      catchError(error => {
        console.error('Error sending Stripe payment details:', error);
        return of(null); // Restituisce un valore nullo in caso di errore
      })
    ).subscribe();  // Sottoscrivi senza callback, gestione nel pipe
  }
  loadStripeScript(): void {
    if (!window.document.getElementById('stripe-script')) {
      const script = window.document.createElement('script');
      script.id = 'stripe-script';
      script.src = 'https://checkout.stripe.com/checkout.js';
      window.document.body.appendChild(script);
    }
  }
}

Gestione delle Risposte delle API

Dopo aver inviato i dettagli del pagamento al server, possiamo gestire la risposta per confermare all'utente che la transazione è stata completata con successo. Utilizzeremo l'oggetto di risposta per fornire un feedback più dettagliato.

Aggiornamento dell'Interfaccia Utente

Modifichiamo i componenti per riflettere lo stato del pagamento. Creiamo una variabile paymentStatus e aggiorniamo l'interfaccia utente di conseguenza.

sendPaymentDetails(paymentDetails: any) {
    this.http.post('https://your-server.com/api/payments', paymentDetails).pipe(
      tap(response => {
        this.paymentStatus = 'success';
        console.log('Payment details sent to the server:', response);
      }),
      catchError(error => {
        this.paymentStatus = 'error';
        console.error('Error sending payment details:', error);
        return of(null); // Restituisce un valore alternativo in caso di errore
      })
    ).subscribe(); // La sottoscrizione avviene, ma senza callback espliciti
  }

Nel template HTML possiamo mostrare un messaggio diverso in base allo stato del pagamento:

<div class="container mt-5">
  <h2 class="text-center">Paga con PayPal</h2>
  <div id="paypal-button-container" class="mt-4"></div>
  <div *ngIf="paymentStatus === 'success'" class="alert alert-success">
    Pagamento completato con successo!
  </div>
  <div *ngIf="paymentStatus === 'error'" class="alert alert-danger">
    Si è verificato un errore durante il pagamento. Riprova.
  </div>
</div>

Facciamo lo stesso in StripePaymentComponent:

paymentStatus: string = ''; //aggiungi la variabile
  ngOnInit(): void {
    this.loadStripeScript();  // Carica lo script di Stripe all'inizio
  }
  makePayment(amount: number): void {
    const paymentHandler = (window).StripeCheckout.configure({
      key: this.stripeAPIKey,
      locale: 'auto',
      token: (stripeToken: any) => {
        console.log(stripeToken);
        this.sendStripePaymentDetails(stripeToken);  // Invia il token al server
      },
    });
    paymentHandler.open({
      name: 'Esempio Applicazione Angular',
      description: 'Pagamenti con Stripe',
      amount: amount * 100,  // Importo in centesimi
    });
  }
  sendStripePaymentDetails(token: any) {
    this.http.post('https://your-server.com/api/stripe-payments', token).pipe(
      tap(response => {
        this.paymentStatus = 'success';
        console.log('Stripe payment details sent to the server:', response);
      }),
      catchError(error => {
        this.paymentStatus = 'error';
        console.error('Error sending Stripe payment details:', error);
        return of(null); // Restituisce un valore nullo in caso di errore
      })
    ).subscribe();  // Sottoscrivi senza callback, gestione nel pipe
  }

Aggiorniamo di conseguenza il template:

<div class="container mt-5">
  <h2 class="text-center">Paga con Stripe</h2>
  <div class="text-center mt-4">
    <button class="btn btn-dark" (click)="makePayment(25)">Stripe</button>
  </div>
  <div *ngIf="paymentStatus === 'success'" class="alert alert-success">
    Pagamento completato con successo!
  </div>
  <div *ngIf="paymentStatus === 'error'" class="alert alert-danger">
    Si è verificato un errore durante il pagamento. Riprova.
  </div>
</div>

Esecuzione del test

Ora esegui un test di pagamento con stripe. Ad esempio:

Come si può notare stiamo ottenendo un risposta di errore, quindi apriamo la console ed indaghiamo:

L'errore che stiamo riscontrando è legato alla politica CORS (Cross-Origin Resource Sharing). Questo significa che il browser sta bloccando la richiesta perché il server a cui stai tentando di accedere non consente richieste da altre origini (in questo caso, da http://localhost:4200).

Possibili soluzioni

Una soluzione potrebbe essere quella di utilizzare un Proxy Angular. Puoi configurare Angular per usare un proxy durante lo sviluppo, quindi crea un file proxy.conf.json nella root principale del progetto con il seguente contenuto:

{
  "/api": {
    "target": "http://localhost:4200",
    "secure": true,
    "changeOrigin": true,
    "logLevel": "debug"
  }
}

Poi modifica il comando di avvio in package.json per includere il proxy:

"scripts": {
  "start": "ng serve --proxy-config proxy.conf.json"
}

In questo modo, tutte le richieste ad /api verranno instradate attraverso il tuo server di sviluppo, evitando i problemi CORS che sono da scongiurare in produzione.

Creare un Backend temporaneo

Un'altra soluzione potrebbe essere quella di creare un Backend temporaneo, ad esempio con Node.js ed Express per gestire le chiamate a Stripe. Prima di tutto dovresti installare Express:

npm install express cors body-parser

Ed ecco l'esempio di un possibile server:

const express = require('express');
const cors = require('cors');
const bodyParser = require('body-parser');
const app = express();
app.use(cors());
app.use(bodyParser.json());
app.post('/api/stripe-payments', (req, res) => {
  // Invia i dettagli a Stripe qui
  res.send({ status: 'success' }); // Risposta di esempio
});
app.listen(3000, () => {
  console.log('Server in ascolto sulla porta 3000');
});

Dopo aver avviato questo server dovremmo modificare il codice Angular per inviare richieste a http://localhost:3000/api/stripe-payments.

Conclusione

In questo articolo abbiamo integrato i pagamenti di PayPal e Stripe nella nostra applicazione Angular. Avendo già configurato i componenti PayPalPaymentComponent e StripePaymentComponent abbiamo aggiunto logiche per gestire gli eventi di pagamento e aggiornare l'interfaccia utente in base allo stato delle transazioni.

Siamo poi passati alla gestione de gli eventi di pagamento con Angular, catturando il successo o il fallimento delle transazioni e aggiornando l'interfaccia utente di conseguenza. Inoltre, è stato affrontato il problema delle risposte delle API. Gestendo gli stati di successo ed errore in modo che gli utenti potessero ricevere un feedback chiaro.

Infine, si è discusso delle problematiche relative al CORS e delle possibili soluzioni. Come l'uso di un proxy Angular o la creazione di un semplice backend con Node.js ed Express. Queste soluzioni ci permettono di testare efficacemente l'integrazione dei pagamenti e di preparare il nostro progetto per la produzione.

Ti consigliamo anche