require_once("MedodoDiPagamento.php");
class Stripe extends MedodoDiPagamento{
var $nome_metodo = "Carta di credito";
var $nomeVenditore = null;
var $publishableKey = null;
var $secretKey = null; //può essere anche una Chiavi con limitazioni (testato 07/2025)
var $endpointSecretKey = null;// You can find your endpoint's secret in your webhook settings
//se impostata viene salvato il cliente su stripe e chiamata questa funzione con l'id da salvare, se c'è un importo viene anche fatta la transazione altrimenti cambiano i testi e viene fatto il solo salvataggio
var $saveCustomer = true;//true/false oppure una funzione per salvare l'id e ripassarlo con:
var $getCustomer = null;//funzione che recupera l'id Stripe per avere la lista delle carte salvate e utilizzarle
var $preAuth = false;//da testare e da aggiornare le diciture
var $saveCard = 'on_session';//off_session / on_session
var $onNewCard;//funzione da chiamare quando viene salvata una nuova carta per i pagamenti futuri ($this->saveCard = true)
var $saveCustomerOnlyIntroHtml = "Inserisci i dati della carta su cui potremo eventualmente fare addebiti";
var $sddIntroHtml = "Inserisci le coordinate del conto corrente di addebito";
var $saveCustomerOnlyButtonText = "Autorizzo addebiti su questa carta";
var $sddButtonText = "Autorizzo addebiti su questo conto corrente";
var $authErrorText = "Errore nei parametri di configurazione Stripe";
var $sddBeneficiario = "TNX srl";
//tutte le lingue qui: https://docs.stripe.com/payments/sepa-debit/set-up-payment?platform=web&payment-ui=direct-api#add-and-configure-an-iban-element
//By providing your payment information and confirming this payment, you authorise (A) ####BENEFICIARIO#### and Stripe, our payment service provider, to send instructions to your bank to debit your account and (B) your bank to debit your account in accordance with those instructions. As part of your rights, you are entitled to a refund from your bank under the terms and conditions of your agreement with your bank. A refund must be claimed within 8 weeks starting from the date on which your account was debited. Your rights are explained in a statement that you can obtain from your bank. You agree to receive notifications for future debits up to 2 days before they occur.
var $sddAccettazione = "Fornendo i dati di pagamento e confermando il pagamento, l’utente autorizza (A) ##BENEFICIARIO## e Stripe, il fornitore del servizio di pagamento locale, a inviare alla sua banca le istruzioni per eseguire addebiti sul suo conto e (B) la sua banca a effettuare addebiti conformemente a tali istruzioni. L’utente, fra le altre cose, ha diritto a un rimborso dalla banca, in base a termini e condizioni dell’accordo sottoscritto con l’istituto. Il rimborso va richiesto entro otto settimane dalla data dell’addebito sul conto. I diritti dell’utente sono illustrati in una comunicazione riepilogativa che è possibile richiedere alla banca. L’utente accetta di ricevere notifiche per i futuri addebiti fino a due giorni prima che vengano effettuati.";
//OLD var $sddAccettazione = "Fornendo l'IBAN e confermando il pagamento, autorizzi TNX Srl e Stripe Inc, gestore dei pagamenti, a inviare istruzioni alla banca per effettuare addebiti sul conto indicato. Avrai la possibilità di chiedere un rimborso alla banca secondo gli accordi contrattuali stipulati. I rimborsi possono essere richiesti entro 8 settimane dalla data di addebito.";
var $saveCustomerOnlyEndText = "La procedura di autorizzazione è andata a buon fine";
var $abbonamento = '';//id del piano da sottoscrivere
//al completamento della procedura il pagamento non è andato a buon fine, mettere a false per non triggerare confermato()
//si possono attivare i webhook "charge.failed" e "charge.succeeded", ma non ho chiaro come ricollegarci all'identificativo del pagamento (in questo evento viene ritornato il customer id, che potrei salvarmi abbinandolo all'identificativo durante la sottoscrizione, ma non so se c'è anche un modo più elegante)
var $sottoscrizioneAbbonamentoTriggerConfermato = false;
var $restart_params = array("token"=>'');
var $messaggioApplePayVerificaDisponibilita = "Stiamo verificando se il tuo sistema permette di effettuare pagamenti tramite ApplePay";
var $messaggioApplePayDisponibile = "Puoi effettuare il pagamento tramite ApplePay, clicca sul pulsante sotto per procedere con il pagamento.";
var $messaggioApplePayNonDisponibile = "Non puoi effettuare il pagamento tramite ApplePay perché il tuo sistema non supporta questo pagamento.";
var $applePayMerchantNation = "IT";
var $mode = 'paymentintents';//https://stripe.com/docs/payments/checkout/server
//PSD2 READY (SCA):
//"paymentElement" - pagamento sul sito con [link] - conferma sincrona - DA TESTARE LIVE
//"paymentintents" (https://stripe.com/docs/payments/payment-intents/quickstart#manual-confirmation-flow) - pagamento sul sito - conferma sincrona
//"paymentscheckout" (https://stripe.com/docs/payments/checkout/server) - pagamento su stripe - conferma asincrona (richiede creazione webhooks)
//"savecard" (https://stripe.com/docs/payments/cards/saving-cards)
//"sdd"
//"applepay"
//OLD:
//"elements" (default) esperienza in-page
//"checkout" (https://stripe.com/docs/checkout) popup che in più ha la funzione "rember me" per registrare la carta e pagare tramite codice di conferma sms
var $payment_method_types = array("card");//klarna
var $logo128x128 = null;//prima versione checkout (usata?)
var $logo300x300 = null;//paymentscheckout sca ready
var $valuta = 'eur';
var $lingua = "ita";
function setValuta($code){
//Three-letter ISO currency code, in lowercase. => https://www.iso.org/iso-4217-currency-codes.html
$this->valuta = strtolower($code);
}
function demoInfo(){
$dev = "Pannello con credenziali API info@tnx.it/***********";
switch($this->mode){
case 'sdd':
return "
Coordinate bancarie per simulazione pagamento:
DE89370400440532013000: The charge status transitions from pending to succeeded
DE62370400440532013001: The charge status transitions from pending to failed
DE35370400440532013002: The charge succeeds but a dispute is immediately created
".$dev;
case 'paymentscheckout':
$dev .= "
SVILUPPATORI:
va creato un webhook nel backend (va inserita la chiave endpointSecretKey nella configurazione) con indirizzo \"".$this->Procedura->genera_link_agg(array($this->step_var=>"webhook", $this->Procedura->metodo_var=>$this->metodoprocedura_id))."\" e tipi evento \"charge.succeeded\" e \"charge.failed\"";
case 'paymentElement':
case 'paymentintents':
case 'savecard':
return "
Carte per simulazione salvataggio dati:
4242424242424242 (carta standard)
4000002500003155 (autenticazione richiesta solo al primo uso)
4000002760003184 (autenticazione richiesta sempre, non caricabile off-session)
4000008260003178 (per simulare errore)
(cvv2 / scadenza qualsiasi, qui tutte le carte).
".$dev;
case 'applepay':
return $dev . "
Seguire questa guida per verifica dominio e inserimento del certificato su stripe";
default:
return "
Carte per simulazione pagamento:
4000003800000008 (italia)
4242424242424242 (usa, verifica cap)
4000000000009995 per simulare errore
(cvv2 / scadenza qualsiasi, qui tutte le carte).
".$dev;
}
}
function ignoreSetupError(){
if(in_array($_GET[$this->step_var], array('webhook'))) return true;
return false;
}
function handleWebhook(){
$this->pulisciOutput();
// mail("c@localhost", "Debug", __FILE__.":".__LINE__."\n".print_r(array($_REQUEST, $_SERVER, file_get_contents("php://input")), true));
require_once($GLOBALS['DATI']['libPath'].'/stripe/init.php');
\Stripe\Stripe::setApiKey($this->secretKey);
// $this->endpointSecretKey = 'whsec_zn1aC84Unj7HNosX5FweiBobkRH4I8Yx';
// mail("c@localhost", "handleWebhook Stripe input", file_get_contents('php://input'));
if(!$_SERVER['HTTP_STRIPE_SIGNATURE']){
$errore = "Richiesta non firmata";
}
else if(!$this->endpointSecretKey){
$errore = "Secret key non configurata";
}
else{
try {
$event = \Stripe\Webhook::constructEvent(
@file_get_contents('php://input'),
$_SERVER['HTTP_STRIPE_SIGNATURE'],
$this->endpointSecretKey
);
}
catch(\UnexpectedValueException $e){
$errore = "Invalid payload";
}
catch(\Stripe\Error\SignatureVerification $e){
$errore = "Invalid signature";
}
}
if($errore){
trigger_error($errore);
$this->Procedura->comunicazione_s2s($this->identificativo, $errore);
http_response_code(400);
die($errore);
}
else http_response_code(200);
$debugInfo = "http".(!empty($_SERVER['HTTPS']) && $_SERVER['HTTPS'] != 'off' ? 's' : '')."://".$_SERVER['SERVER_NAME'].$_SERVER['REQUEST_URI']."\n".__FILE__.":".__LINE__."\n".print_r($event, true);
if($event->data->object->metadata && property_exists($event->data->object->metadata, "identificativo_webhook")){
$identificativo_webhook = $event->data->object->metadata->identificativo_webhook;
}
else if(property_exists($event->data->object, "source") && $event->data->object->source->metadata && property_exists($event->data->object->source->metadata, "identificativo_webhook")){
//per gli abbonamenti sono riuscito a trovare il modo di passarlo solo sul source
$identificativo_webhook = $event->data->object->source->metadata->identificativo_webhook;
}
else $identificativo_webhook = '';
// mail("c@localhost", get_class($event->data->object), __FILE__.":".__LINE__."\n".print_r(array($_REQUEST, $_SERVER), true));
if($identificativo_webhook){//se non c'è è un pagamento paymentintents e la s2s viene gestita diversamente
if(in_array($event->type, array('charge.succeeded'))){
if($event->data->object->outcome->type != 'authorized'){
$this->Procedura->comunicazione_s2s($identificativo_webhook, $event->data->object->outcome->seller_message);
$this->Procedura->comunicazione_s2s($identificativo_webhook, print_r($event->data->object, true));
trigger_error("Pagamento non autorizzato, probabile rischio frode avvertire il cliente: ".$event->data->object->outcome->seller_message);
}
else{
mail("c@localhost", "Controlla questo evento per inviare le notifiche al provve per i pagamenti falliti", $debugInfo);
$this->Procedura->comunicazione_s2s($identificativo_webhook, print_r($event->data->object, true));
$this->Procedura->confermato($identificativo_webhook);
}
}
else if($event->type == 'charge.failed') {
$this->Procedura->comunicazione_s2s($identificativo_webhook, "Addebito fallito");
}
else{
mail("c@localhost", "Evento Stripe imprevisto", $debugInfo);
}
}
else if(get_class($event->data->object) == 'Stripe\Invoice'){
if(method_exists($this->Procedura, "ricorrenzaStripe")) $this->Procedura->ricorrenzaStripe($event);
if(!in_array($event->type, [
'invoice.created',
'invoice.deleted',
// 'invoice.finalization_failed',
'invoice.finalized',
// 'invoice.marked_uncollectible',
// 'invoice.overdue',
'invoice.paid',
// 'invoice.payment_action_required',
// 'invoice.payment_failed',
'invoice.payment_succeeded',
'invoice.sent',
'invoice.upcoming',
'invoice.updated',
'invoice.voided',
'invoice.will_be_due',
])){
$mailSubj = ucfirst($event->type).(property_exists($event->data->object, "source")?" ".$event->data->object->source->owner->name . " " . $event->data->object->source->owner->email:"");
}
}
else if(get_class($event->data->object) == 'Stripe\Dispute'){
//dispute (non hanno proprietà payment_method_details)
$mailSubj = ucfirst($event->type)." ".$event->data->object->reason." (".$event->data->object->payment_intent.")";
}
else if($event->data->object->payment_method_details->type == 'sepa_debit'){
//sepa di ordinalo, andranno gestiti sul sito quando verranno usati anche da altri
if($event->type != 'charge.succeeded'){
$mailSubj = ucfirst($event->type).(property_exists($event->data->object, "source")?" ".$event->data->object->source->owner->name . " " . $event->data->object->source->owner->email:"");
}
}
else{
// mail("c@localhost", "Questo dovrebbe essere un handleWebhook di un pagamento paymentintents (s2s gestita a parte)", $debugInfo);
}
// if($mailSubj) mail("carlo@tnx.it", $mailSubj, $debugInfo);
if($mailSubj) mail("andrea@tnx.it", $mailSubj, $debugInfo);
$this->pulisciOutput();
http_response_code(200);
die();
}
function indiLingua(){
switch($GLOBALS['DATI']["lang"]) {
case "ita":
$this->lingua = "ita";
break;
case "fra":
$this->lingua = "fra";
break;
case "spa":
$this->lingua = "spa";
break;
case "ger":
$this->lingua = "ted";
break;
default:
$this->lingua = "ing";
break;
}
}
function placeholderIntestatario(){
return $this->lingua == 'ita' ? "Nome intestatario" : "Cardholder name";
}
function rimborsa(){
$result = $this->stripeApiCall(
"https://api.stripe.com/v1/refunds",
array(
"payment_intent" => $this->Procedura->infoRimborso['identificativo_pagamento']
)
);
if($result['amount']){
$this->Procedura->logga(array(
'identificativo_ordine' => $this->identificativo,
'ultimo_stato' => 'Rimborso preso in carico: '.($result['amount']/100).$result['currency'].' '.$result['status'].' ('.$result['id'].')'
));
// $this->Procedura->logga(array(
// 'identificativo_ordine' => $this->identificativo,
// 'ultimo_stato' => 'Procedura di rimborso completata'
// ));
return 'ok';//tutto ok
}
else{
$this->Procedura->logga(array(
'identificativo_ordine' => $this->identificativo,
'ultimo_stato' => 'Errore durante il rimborso'."\n".print_r($result, true)
));
return $result['error']['message'];
}
// Array
// (
// [id] => re_1HSnBfERz1qJ9aShycQh0YiM
// [object] => refund
// [amount] => 1950
// [balance_transaction] => txn_1HSnBgERz1qJ9aShJpFqczEs
// [charge] => ch_1HSmbYERz1qJ9aShB7VZifu0
// [created] => 1600449355
// [currency] => eur
// [metadata] => Array
// (
// )
// [payment_intent] => pi_1HSmbSERz1qJ9aShwtZAAGb1
// [reason] =>
// [receipt_number] =>
// [source_transfer_reversal] =>
// [status] => succeeded
// [transfer_reversal] =>
// )
}
function paymentintentsAjax(){
$this->pulisciOutput();
if($GLOBALS['DATI']['dove_sono'] == 'loc'){
$GLOBALS['_dev_email'] = "c@localhost";
$GLOBALS['CONF']['indi_error'] = "NO";//così mi arrivano almeno per email, altrimenti li perdo perchè l'output inizia e finisce in questa funzione
// restore_error_handler();//se faccio così non scatta il "filtro" che ignora alcuni tipi di errori (ne stampa molti del tipo "Declaration of XXX should be compatible with")
}
$input = file_get_contents("php://input");
if(!$input) die;//su manjodelivery.it tutte le mattine arrivavano richieste in GET (da edge), forse un proxy, un virus, uno strano plugin
// if(!$input){
//togliere tra qualche giorno di test 15/3/2021
// mail("c@localhost", "paymentintents Ajax senza POST data", __FILE__.":".__LINE__."\n".print_r(array($input, $_POST, $_GET, $_SERVER), true));
// die;
// }
$postedJson = json_decode($input);
if($postedJson->removeCard){
$res = $this->stripeApiCall("https://api.stripe.com/v1/payment_methods/".$postedJson->removeCard."/detach");
//Returns a PaymentMethod object.
echo json_encode([
"success" => isset($res['id'])
]);
}
else{
if($postedJson->payment_method_id){//richiedo l'addebito, potrebbe essere richiesta la conferma all'utente oppure no
$payData = array(
"payment_method" => $postedJson->payment_method_id,
"amount" => round($this->importo*100),
"description" => $this->descrizione,
"currency" => $this->valuta,
"confirmation_method" => "manual",
"confirm" => "true",
//necessario per nuove versioni api da 16/10/2023 https://stripe.com/docs/upgrades/manage-payment-methods
'payment_method_types' => ['card']
//alternativa:
//'automatic_payment_methods' => ['enabled' => 'true', 'allow_redirects'=>'never'],
//'confirmation_method' => null
);
if($this->preAuth) $payData['capture_method'] = "manual";//preautorizzazione
if($postedJson->customerId){
$payData['customer'] = $postedJson->customerId;//per utilizzo una carta salvata
//attacco la carta al cliente esistente
if($postedJson->saveCard){
$this->stripeApiCall(
"https://api.stripe.com/v1/payment_methods/".$postedJson->payment_method_id."/attach",
array(
"customer" => $postedJson->customerId
)
);
if($this->onNewCard) call_user_func($this->onNewCard, $this->identificativo, $postedJson->customerId, $postedJson->payment_method_id);
}
}
else if($this->saveCustomer){//posso salvarlo anche senza salvare le carte
$customerData = array(
"email" => trim($this->cliente_email),
"name" => $this->cliente_nome,
"description" => $this->cliente_nome . ($this->cliente_riferimento ? " (".$this->cliente_riferimento.")" : ""),//viene esportato questo
);
if($postedJson->saveCard){
$payData["setup_future_usage"] = $this->saveCard;
$customerData['payment_method'] = $postedJson->payment_method_id;
}
$res = $this->stripeApiCall(
"https://api.stripe.com/v1/customers",
$customerData
);
if($res['id']){
if($postedJson->saveCard){
if($this->onNewCard) call_user_func($this->onNewCard, $this->identificativo, $res['id'], $postedJson->payment_method_id);
}
$payData['customer'] = $res['id'];
if(is_callable($this->saveCustomer) && call_user_func($this->saveCustomer, $this->identificativo, $res['id'])){
$this->Procedura->comunicazione_s2s($this->identificativo, "Cliente registrato: ".$res['id']);
}
}
else if($res['error']){
//sembra che se durante l'abbinamento la carta venga validata (una carta senza fondi viene abbinata, quindi si parla di una carta invalida proprio) e possa quindi dare errore (lo' darà verosimilmente anche alla chiamata payment_intents più sotto)
// esempio del 28/5/21:
// "php://input" => {"payment_method_id":"pm_1Iw9TZKYMa4MmUtpL7ZRWtbC","saveCard":true,"customerId":""}
// $customerData => Array
// (
// [email] => imielzarek@gmail.com
// [name] => ivan mielzare
// [description] => ivan mielzare
// [payment_method] => pm_1Iw9TZKYMa4MmUtpL7ZRWtbC
// )
// $res => Array
// (
// [code] => card_declined
// [decline_code] => do_not_honor
// [doc_url] => https://stripe.com/docs/error-codes/card-declined
// [message] => Your card was declined.
// [param] =>
// [type] => card_error
// )
}
else{
mail(
"c@localhost",
"Cliente Stripe non registrato controllare",
__FILE__.":".__LINE__."\n".print_r(array(file_get_contents("php://input"), $customerData, $res), true)
);
}
}
$intent = $this->stripeApiCall(
"https://api.stripe.com/v1/payment_intents",
$payData
);
// mail("c@localhost", "Oggetto", wordwrap(print_r($intent, true), 70, "\r\n"), "MIME-Version: 1.0\r\nContent-type: text/html; charset=utf-8\r\n");
if($intent['error_tnx'] == 'auth'){
echo json_encode(['error' => $this->authErrorText]);
die;
}
}
else if($postedJson->payment_intent_id){//il pagamento ha richiesto una conferma PSD2/SCA (response.requires_action)
$intent = $this->stripeApiCall(
"https://api.stripe.com/v1/payment_intents/".$postedJson->payment_intent_id."/confirm"
);
}
//On versions of the API before 2019-02-11, requires_payment_method appears as requires_source and requires_action appears as requires_source_action.
if(in_array($intent["status"], array('requires_action', 'requires_source_action')) && $intent["next_action"]['type'] == 'use_stripe_sdk') {
# Tell the client to handle the action
echo json_encode([
'requires_action' => true,
'payment_intent_client_secret' => $intent['client_secret']
]);
} else if ($intent["status"] == 'succeeded' || ($this->preAuth && $intent["status"] == 'requires_capture')) {
# The payment didn’t need any additional actions and completed!
# Handle post-payment fulfillment
//$payment_intent_id = $postedJson->payment_intent_id c'è in test, ma non sempre live (sirio_verona)
$payment_intent_id = $intent['id'];
if($postedJson->savedCard && $this->onSavedCardUse) call_user_func($this->onSavedCardUse);
$this->Procedura->comunicazione_s2s($this->identificativo,
"Importo ricevuto: ".number_format($intent['amount']/100, 2, ",", "")."€ (ID: ".$payment_intent_id.")"
// ."cliente: ".$res['source']['name'].", "
// ."ID: ".$res['balance_transaction']
);
// mail("c@localhost", "Debug Stripe", __FILE__.":".__LINE__."\n".print_r(array($postedJson, $intent, $_SERVER), true));
$this->Procedura->confermato($this->identificativo, null, $payment_intent_id);
echo json_encode([
"success" => true
]);
} else if ($intent["error"]) {
if($intent["error"]['code'] == 'card_decline_rate_limit_exceeded') $message = 'Troppi tentativi con questa carta, riprova tra 24 ore';
else $message = $intent['error']["message"];
$this->Procedura->comunicazione_s2s($this->identificativo,
"Errore inviato al cliente: ".$message
);
echo json_encode(['error' => $message]);
} else {
//successo una volta durante pagamento test terredelbruno + chefawayvilladarte
mail("c@localhost", "Stripe Invalid PaymentIntent status", __FILE__.":".__LINE__."\n".print_r(array(file_get_contents("php://input"), $postedJson, $intent, $_POST, $_GET, $_SERVER), true));
# Invalid status
http_response_code(500);
echo json_encode(['error' => 'Invalid PaymentIntent status']);
}
}
die;
}
function paymentElementHtml(){
$di = $this->demo ? $this->demoInfo() : '';
if($di) $di = '
' . $this->messaggioApplePayVerificaDisponibilita . '
Errore creazione prodotto:';
// $debugBacktrace = debug_backtrace(); array_unshift($debugBacktrace, array('file'=>__FILE__, 'line'=>__LINE__, 'function'=>'debugTnx')); foreach($debugBacktrace as $debugLine) echo "".str_replace("/tnx/www/html/www/", "", $debugLine['file']).""." ".$debugLine['function']."()
";
$printMe = $res; ob_start(); if(is_object($printMe)||is_array($printMe)) print_r($printMe); else var_dump($printMe); echo htmlentities(ob_get_clean(), ENT_COMPAT|ENT_HTML401|ENT_SUBSTITUTE, 'UTF-8');
echo '';
die;
}
//https://stripe.com/docs/api/plans
$res = $this->stripeApiCall(
"https://api.stripe.com/v1/plans",
array(
"product" => $res['id'],
"nickname"=>$nomePiano,
"interval"=>'month',
"currency"=>$this->valuta,
"amount"=> 89 * 100,
)
);
echo 'Piano creato:';
// $debugBacktrace = debug_backtrace(); array_unshift($debugBacktrace, array('file'=>__FILE__, 'line'=>__LINE__, 'function'=>'debugTnx')); foreach($debugBacktrace as $debugLine) echo "".str_replace("/tnx/www/html/www/", "", $debugLine['file']).""." ".$debugLine['function']."()
";
$printMe = $res; ob_start(); if(is_object($printMe)||is_array($printMe)) print_r($printMe); else var_dump($printMe); echo htmlentities(ob_get_clean(), ENT_COMPAT|ENT_HTML401|ENT_SUBSTITUTE, 'UTF-8');
echo '';
die;
case 'webhook':
return $this->handleWebhook();
case 'verify':
$data = $this->stripeApiCall("https://api.stripe.com/v1/payment_intents/".$_GET['payment_intent']);
if($data["status"] != 'succeeded'){
trigger_error($data['last_payment_error']);
$this->Procedura->comunicazione_s2s($this->identificativo, "Errore: ".$data['last_payment_error']);
$redirectStep = "error";
}
else{
$redirectStep = "return_ok";
$this->Procedura->comunicazione_s2s($data["metadata"]["identificativo_webhook"], "Importo ricevuto: ".($data["amount_received"]/100).$data["currency"]);
$this->Procedura->confermato($data["metadata"]["identificativo_webhook"]);
}
$this->Procedura->redirect($this->Procedura->genera_link_agg(array("payment_intent_client_secret"=>"","redirect_status"=>"","payment_intent"=>"",$this->step_var=>$redirectStep)));
return;
case 's2s':
//se rubo un token non lo posso utilizzare più di una volta
//se cambio l'url per la s2s semplicemente pago l'ordine di un altro perchè l'importo autorizzato non è vincolante
$identificativo = $this->identificativo;
$procediAddebitoImporto = true;
if($this->saveCustomer || $this->abbonamento){
if(!$_GET['customer_id']){//in questo caso è creato da sddInit
$nome = $this->cliente_nome;
$data = array(
"email" => $this->cliente_email,
"name" => $nome,
"description" => $nome . ($this->cliente_riferimento ? " (".$this->cliente_riferimento.")" : ""),//viene esportato questo
);
}
$url = "https://api.stripe.com/v1/customers";
if($_GET['customer_id']){
$customerId = $_GET['customer_id'];
$url .= "/" . $customerId;
$data['invoice_settings']['default_payment_method'] = $_GET['pM'];
}
else{
$data['payment_method'] = $_GET['token'];
if($this->abbonamento) $data['invoice_settings']['default_payment_method'] = $_GET['token'];
}
$res = $this->stripeApiCall(
$url,
$data
);
if(!$_GET['customer_id']) $customerId = $res['id'];
// mail("a.toce@tnx.it", "Debug", __FILE__.":".__LINE__."\n".print_r(array($res, $_REQUEST, $_SERVER), true));
// mail("c@localhost", "Debug", __FILE__.":".__LINE__."\n".print_r(array($res, $_REQUEST, $_SERVER), true));
if($res['error_tnx'] == 'auth'){
return $this->Procedura->errore($this->authErrorText);
}
else if($res['error'] && $err = $res['error']['message']){
$this->Procedura->comunicazione_s2s($identificativo, "Error: ".$err);
return $this->Procedura->errore($err);
}
else if($customerId){
if(is_callable($this->saveCustomer)){
if(call_user_func($this->saveCustomer, $identificativo, $customerId)){
$this->Procedura->comunicazione_s2s($identificativo, "Cliente registrato: ".$customerId);
$redirectStep = "return_ok";
}
else{
$this->Procedura->comunicazione_s2s($identificativo, "Errore: ".print_r($res, true));
$procediAddebitoImporto = false;
$redirectStep = "error";
}
}
else if($this->mode == 'savecard'){
$msg = "Non è stato impostato il metodo saveCustomer";
$this->Procedura->comunicazione_s2s($identificativo, $msg);
trigger_error($msg);
$redirectStep = "error";
}
else $this->Procedura->comunicazione_s2s($identificativo, "Cliente Stripe: ".$customerId);
if($this->abbonamento){
if(is_array($this->abbonamento)){
$abbonamenti = $this->abbonamento;
}
else $abbonamenti = [['plan' => $this->abbonamento]];
$allOk = true;
foreach($abbonamenti as $k=>$callData){
$callData["customer"] = $customerId;
$resSub = $this->stripeApiCall("https://api.stripe.com/v1/subscriptions", $callData);
$nome = "abbonamento ".(is_string($this->abbonamento)?$this->abbonamento:($k+1));
if(in_array($resSub['status'], ['active', 'trialing'])){
$this->Procedura->comunicazione_s2s($identificativo, ucfirst($nome)." sottoscritto: ".$resSub['id']);
}
else{
$this->Procedura->comunicazione_s2s($identificativo, "Errore $nome: ".print_r($resSub, true));
$allOk = false;
}
}
if($allOk){
$this->Procedura->confermato($identificativo, $resSub);
$redirectStep = "return_ok";
}
else{
$procediAddebitoImporto = false;
$redirectStep = "error";
}
}
}
}
if($this->importo && $procediAddebitoImporto){
$data = array(
"amount" => round($this->importo*100),
"description" => $this->descrizione,
"currency" => $this->valuta,
);
if($_GET['sdd']){//source e charge per sdd sono stati deprecati
$data['customer'] = $customerId;
$data['payment_method'] = $_GET['pM'];
$data['off_session'] = 'true';
$data['confirm'] = 'true';
$data['payment_method_types[]'] = 'sepa_debit';
// print_r_tnx($data, $_SERVER['REMOTE_ADDR'] == '192.168.0.177') || die;
$pi = $this->stripeApiCall(
"https://api.stripe.com/v1/payment_intents",
$data
);
if($pi['last_payment_error']){
trigger_error($pi['last_payment_error']);
$this->Procedura->comunicazione_s2s($identificativo, "Errore: ".$pi['last_payment_error']);
$redirectStep = "error";
}
else{
$redirectStep = "return_ok";
$this->Procedura->comunicazione_s2s($identificativo, "Addebito SEPA avviato");
$this->Procedura->confermato($identificativo);
}
}
else{
if(!$customerId) $data['source'] = $_GET['token'];
else $data['customer'] = $customerId;
$res = $this->stripeApiCall(
"https://api.stripe.com/v1/charges",
$data
);
// mail("a.toce@tnx.it", "Debug", __FILE__.":".__LINE__."\n".print_r(array($res, $_REQUEST, $_SERVER), true));
if($res['error']['type'] == 'invalid_request_error'){//errore nostro
$redirectStep = "error";
}
else if($res['object'] != 'charge' || ($this->mode != 'sdd' /* sdd non è immediatamente paid */ && !$res['paid'])){
$this->Procedura->comunicazione_s2s($identificativo, "Errore: ".print_r($res, true));
$redirectStep = "error";
}
else{
//https://stripe.com/docs/api/curl#charge_object
if($res['fraud_details']){
$msg = "Dettagli frode ricevuti da Stripe: ".implode(", ", $res['fraud_details']);
$this->Procedura->comunicazione_s2s($identificativo, $msg);
trigger_error($msg);
}
if($res['outcome']['type'] != 'authorized'){
$msg = "Pagamento accettato, ma rischio frode segnalato da Stripe: ".$res['outcome']['seller_message']." (".$res['outcome']['reason'].")";
$this->Procedura->comunicazione_s2s($identificativo, $msg);
trigger_error($msg);
}
$this->Procedura->comunicazione_s2s($identificativo, print_r($res, true));// $res['balance_transaction'] non c'è sempre (vedi cliente svizzero amato.vito86@gmail.com)
$this->Procedura->comunicazione_s2s($identificativo,
"Importo ricevuto: ".number_format($res['amount']/100, 2, ",", "")."€, ".
"cliente: ".$res['source']['name'].", ".
"ID: ".$res['balance_transaction']
);
$this->Procedura->confermato($identificativo);
$redirectStep = "return_ok";
}
}
}
// echo ''; // $printMe = $res; if(is_object($printMe)||is_array($printMe)) print_r($printMe); else var_dump($printMe); // echo ''; // die; $this->Procedura->redirect($this->Procedura->genera_link_agg(array("token"=>"",$this->step_var=>$redirectStep))); break; } } } // [id] => ch_1BvOdAERz1qJ9aShdYIaq8yb // [object] => charge // [amount] => 999 // [amount_refunded] => 0 // [application] => // [application_fee] => // [balance_transaction] => txn_1BvOdAERz1qJ9aShsNEq19qS // [captured] => 1 // [created] => 1518608456 // [currency] => eur // [customer] => // [description] => // [destination] => // [dispute] => // [failure_code] => // [failure_message] => // [fraud_details] => Array // ( // ) // [invoice] => // [livemode] => // [metadata] => Array // ( // ) // [on_behalf_of] => // [order] => // [outcome] => Array // ( // [network_status] => approved_by_network // [reason] => // [risk_level] => normal // [seller_message] => Payment complete. // [type] => authorized // ) // [paid] => 1 // [receipt_email] => // [receipt_number] => // [refunded] => // [refunds] => Array // ( // [object] => list // [data] => Array // ( // ) // [has_more] => // [total_count] => 0 // [url] => /v1/charges/ch_1BvOdAERz1qJ9aShdYIaq8yb/refunds // ) // [review] => // [shipping] => // [source] => Array // ( // [id] => card_1BvOd6ERz1qJ9aShbh9PpTMb // [object] => card // [address_city] => // [address_country] => // [address_line1] => // [address_line1_check] => // [address_line2] => // [address_state] => // [address_zip] => // [address_zip_check] => // [brand] => Visa // [country] => US // [customer] => // [cvc_check] => pass // [dynamic_last4] => // [exp_month] => 12 // [exp_year] => 2019 // [fingerprint] => hdfRV57FLixgF2J0 // [funding] => credit // [last4] => 4242 // [metadata] => Array // ( // ) // [name] => carlo@tnx.it // [tokenization_method] => // ) // [source_transfer] => // [statement_descriptor] => // [status] => succeeded // [transfer_group] => } ?>