Javascript, HTML, CSS e... !
0 commenti

Utilizzando un'applicazione web creata con Google Apps Script

IPN Listener per ottenere le notifiche immediate di pagamento da Paypal

Il servizio IPN di Paypal, o Notifica immediata del pagamento, ti informa dei pagamenti ricevuti da PayPal (ottenendo l'effettiva conferma delle transazioni) inviando le informazioni di pagamento ad un'applicazione web esterna, che può essere un servizio a pagamento come quello offerto da Zapier, per automatizzare attività e processi in generale, oppure la creazione a costo zero di una pagina all'interno del proprio sito dedicata allo scopo o ancora più facilmente avvalendosi di un listener in Google Apps Script.

Gli esempi di implementazione del listener IPN, sul sito di PayPal, non contengono alcun codice di esempio in Javascript da poter utilizzare con gli script di Google, tuttavia esiste uno script presente su GitHub, chiamato PayPal-IPN-Listener-Google-Script, che ho testato in ambiente di sviluppo e che sembra interrogare correttamente i server di Paypal, quantomeno verso un account di prova dove di contro non essendoci effettive transazioni registrate non mi è stato possibile, come prevedibile, ricevere il valore VALID come risposta dal controllo incrociato (mi riservo verifiche successive o conferme/smentite dei lettori di questo articolo in caso di applicazione dello script su un account reale) tuttavia i parametri vengono ricevuti e gestiti correttamente all'interno dello script.
Riporto di seguito il codice del listener (chiamato anche ascoltatore) in modo da facilitare le spiegazioni successive sul suo funzionamento e su quello che PayPal si aspetta di ricevere da tale codice:

function doPost(e) {
  
  // Scrivo all'interno di uno Spreasheet le informazioni presenti nei parametri in modo da poterle verificare visivamente (utile in fase di test)
  var ss = SpreadsheetApp.openById('1VHrk42NeQ615OCGsy21xRx...');
  var sheet = ss.getSheets()[0];
  var cell = sheet.getRange(1,1);
  cell.setValue(e);  
  
  var isProduction = false;

  var strSimulator  = 'https://ipnpb.sandbox.paypal.com/cgi-bin/webscr';
  var strLive = "https://ipnpb.paypal.com/cgi-bin/webscr";
  var paypalURL = strSimulator
  
  if (isProduction)  paypalURL = strLive;
  var payload = "cmd=_notify-validate&" + e.postData.contents;
  payload = payload.replace("+", "%2B");
  
  var options = {
    "method" : "post",
    "payload" : payload,
  };
  
  cell = sheet.getRange(2,1);
  cell.setValue(e.postData.contents);

  var resp = UrlFetchApp.fetch(paypalURL, options); // Controllo integrità dati inviandoli a Paypal per conferma
  
  if (resp == 'VERIFIED') {
    if (e.parameter.payment_status  == 'Completed') {
      if (e.parameter.receiver_email == 'seller@paypalsandbox.com') { // sostituire l'indirizzo mail con quello utilizzato
        
        // Conversione nella valuta di riferimento (nel caso USD) se il pagamento avviene con qualsiasi altra valuta
        var exchangeRate = 1; 
        if ((e.parameter.exchange_rate)) {
          exchangeRate = parseFloat(e.parameter.exchange_rate);
        }
        // La seguente funzione 'isPaymentValid' non è presente nell'esempio e necessita di essere costruita, ha lo scopo di convertire l'importo pagato nella valuta di riferimento (ad esempio USD)
        var paidUSD = isPaymentValid(parseFloat(e.parameter.mc_gross), e.parameter.mc_currency, exchangeRate);
        if (paidUSD == 0.0) {
          return false;
        }
        if (paidUSD > 0.0) {      
          
          // Tutto convalidato, il pagamento può essere elaborato
          var processSuccess = processDownloadRequest(e);

          // In questo momento è possibile inviare i dati a Google Analytics con il protocollo di misurazione
          // Preparo l'oggetto con i parametri da inviare ad Analytics in base a quelli ricevuti
          // Costruisco la stringa del payload con encodeURIComponent
          // Popolo la variabile options con le varie informazioni utili per la chiamata in POST
          // Effettuo la chiamata con UrlFetchApp.fetch('http://www.google-analytics.com/collect', options);
          
          if (!(processSuccess)) {
            // Processo di pagamento non valido
          }
        } else {
          // Valore di pagamento non corrispondente a quello atteso
        }
      } else {
        // Richiesta non originata dal mio account PayPal
      }
    } else {
      // Pagamento non completato
    }
  } else {
    // Risposta da PayPal: INVALID 
  }
}

Per effettuare le prove di funzionamento del servizio IPN ho utilizzato uno strumento di PayPal chiamato IPNSimulator (https://developer.paypal.com/developer/ipnSimulator/), ovvero un tool che può essere utilizzato per inviare messaggi IPN di prova dalla Sandbox di PayPal all'URL in cui è in esecuzione il listener. IPNSimulator consente di verificare che il listener stia ricevendo i messaggi relative alle notifiche di pagamento e li gestisca correttamente.

Quello che pertanto è necessario avere in prima analisi, per ottenere il risultato desiderato con Google Apps Sript, è uno script pubblicato come applicazione web (Fig. 1), eseguita come l'utente che l'ha creata ma con accesso consentito a chiunque (inclusi gli utenti anonimi) e che riceva dati in post, ovvero con la funzione doPost(e) all'interno della quale inserire il resto dei controlli descritti di seguito, per raccogliere la richiesta inviata da PayPal.



distribuzione di uno script google come applicazione web

Fig. 1 - Distribuzione di uno script Google con applicazione web


Una volta ricevuta la chiamata è necessario confermare a PayPal che è il messaggio è stato ricevuto. Ci sono due cose che devono accadere lato Apps Script affinché l'invio di tale conferma sia accettato da PayPal:
- Dopo aver ricevuto il messaggio IPN da PayPal, il listener deve restituire una risposta HTTP 200 vuota a PayPal. In caso contrario, PayPal rinvia il messaggio IPN. Il vantaggio di utilizzare Apps Script, in questo caso, è che la restituzione del codice 200 avviene automaticamente pertanto non è necessario alcun intervento per ottemperare a questo passaggio, l'importante è che non si verifichino errori nel codice di altra natura.
- L'ascoltatore dovrà inviare di nuovo il messaggio completo a PayPal tramite HTTPS POST, con un prefisso nel messaggio 'cmd=_notify-validate', facendo attenzione a non modificare i campi del messaggio, a mantenerne l'ordine così come sono stati ricevuti ed a mantenere la codifica dei caratteri del messaggio originale (come indicato nella documentazione ufficiale https://developer.paypal.com/docs/classic/ipn/integration-guide/IPNSetup/).

Per verifica il funzionamento del proprio listener IPN, come detto a inizio articolo, è possibile utilizzare IPNSimulator (le chiamate inviate da questo sistema contengono un parametro, test_ipn=1, che le differenzia dalle chiamate IPN live). Affinché le chiamate di test vadano a buon fine dovrà essere specificato nello script l'opportuno URL di PayPal da chiamare per la verifica, nel caso specifico del codice di esempio è quello che nello script va a popolare la variabile strSimulator, ottenuto aggiungendo la parola "sandbox" all'URL del postback: https://ipnpb.sandbox.paypal.com/cgi-bin/webscr.

Detto questo, loggandosi alla Dashboard con il proprio account Paypal ed accedendo alla relativa area per gli sviluppatori: https://developer.paypal.com/developer/ipnSimulator/, sarà possibile incollare l'URL dell'applicazione web (quella del nostro script, assicurando di aver pubblicato l'ultima versione funzionante) e selezionare una voce nel tipo di transazione (esempio, eCheck - complete, per ottenere l'informazione del pagamento completato), Fig. 2:



IPNSimulator sul sito di PayPal

Fig. 2 - IPNSimulator accessibile dall'area sviluppatori sul sito di PayPal


Al netto della risposta ottenuta dal controllo incrociato con Paypal (VALID o INVALID), considerando che nello script ho inserito un codice che scrive le informazioni passate al listner all'interno di uno Spreadsheet, Fig. 3, è possibile pertanto visualizzare i parametri appena inviati da IPNSimulator, compreso quello che identifica il test, pronti per essere inviati in POST per quel processo di controllo che prende il nome di handshake.



Parametri passati al listener da IPNSimulator

Fig. 3 - Parametri passati al listener da IPNSimulator


Una volta che il sistema sarà stato messo a regime e verificatone il corretto funzionamento sarà possibile utilizzarlo per la gestione delle transazioni reali, ricordandosi che sarà necessario utilizzare l'URL di postback corretto, ovvero quello che non include la parola sandbox.

Per quanto riguarda invece il tracciamento delle transazioni in Google Analytics, questo sistema garantisce l'invio dei dati verso la piattaforma di analisi senza che vengano perse transazioni dovute al mancato ritorno da PayPal alla pagina di ringraziamento sul proprio sito oppure per via del fatto che l'utente utilizza delle estensioni che possono bloccare i sistemi di tracking.
Sarà quindi possibile inserire nel codice di cui sopra, nel momento in cui tutti i controlli risultano superati con successo, una chiamata con il protocollo di misurazione preparando l'oggetto con i parametri da inviare ad Analytics in base a quelli ricevuti per poi costruire la stringa del payload con la codifica per l'URL al fine di effettuare la chiamata con UrlFetchApp.fetch('http://www.google-analytics.com/collect', options), dove la variabile options contiene le varie informazioni utili per la chiamata in POST.
Un esempio di quanto appena descritto, applicato in un contesto diverso ma con la stessa finalità di tracciare informazioni tramite il protocollo di misurazione di Google Analytics, è presente nell'articolo "Tracciare in Analytics l'apertura di uno Spreadsheet con una Funzione Custom".

Tags

Michele Pisani

Michele Pisani

Sviluppatore Javascript ed esperto in Digital Analytics

L'esperienza nel settore Digital Analytics unita ad anni di sviluppo in Javascript ha trovato la massima espressione in Google Apps Script che mi ha permesso, con estrema facilità e poche righe di codice, di realizzare potenti applicazioni interattive e processi automatizzati integrati con i prodotti della G Suite.

Come contattarmi
scrivi un commento

0 Commenti

Non ci sono commenti

Nessuno ha ancora commentato questo articolo, fallo tu per primo!

scrivi un commento

Scrivi un commento

Il tuo indirizzo email non sarà pubblicato.I campi contrassegnati da un * sono obbligatori
Puoi utilizzare i seguenti tag nei commenti:
[bold]testo[/bold] se vuoi evidenziare un testo con il grassetto[code]function helloworld() { }[/code] se vuoi pubblicare una porzione di codice[url]http://www.appsscript.it[/url] se devi riferirti ad un indirizzo web