function bizz_check_quickpay_response() { global $booking_settings; // get booking settings $opt_s = $booking_settings->get_settings(); if (isset($_GET['qplink'])) { //redirect to payment from cookie ajax redirect. preventing cross domain access error header("location: " . $_GET['qplink']); } if (isset($_GET['quickpay']) && $_GET['quickpay'] == 'cancel') { echo "<script> \n//alert('Transaktion afbrudt');\nloadStepFour(cookie_data); </script>"; } if (isset($_GET['quickpay']) && $_GET['quickpay'] != 'cancel') { // variables $order_id = $_GET['quickpay']; $post_id = $_GET['post']; try { // Initialize require_once dirname(__FILE__) . "/quickpay-api/QuickpayApi.php"; $qp = new QuickpayApi(); //TODO change to seperate QP key $qp->setOptions($opt_s['pay_mollie_api']); $qp->mode = 'payments?order_id='; // Commit the status request, checking valid transaction id $str = $qp->status($order_id); $str["operations"][0] = array_reverse($str["operations"][0]); $qp_status = $str[0]["operations"][0]["qp_status_code"]; $qp_status_msg = $str[0]["operations"][0]["qp_status_msg"]; $qp_order_id = $str[0]["order_id"]; $qp_aq_status_code = $str[0]["aq_status_code"]; $qp_aq_status_msg = $str[0]["aq_status_msg"]; $qp_cardtype = $str[0]["metadata"]["brand"]; $qp_cardnumber = "xxxx-xxxxxx-" . $str[0]["metadata"]["last4"]; $qp_amount = $str[0]["operations"][0]["amount"]; $qp_currency = $str[0]["currency"]; $qp_pending = $str[0]["pending"] == "true" ? " - pending " : ""; $qp_expire = $str[0]["metadata"]["exp_month"] . "-" . $str[0]["metadata"]["exp_year"]; /* 20000 Approved 40000 Rejected By Acquirer 40001 Request Data Error 50000 Gateway Error 50300 Communications Error (with Acquirer) */ add_post_meta($post_id, 'bizzthemes_bookings_qpcomments', ''); switch ($qp_status) { case '20000': update_post_meta($post_id, 'bizzthemes_bookings_status', 'approved'); $comments = "QuickPay Transaction: " . $str["id"] . $qp_pending . ' (' . $qp_cardtype . ' ' . $qp_amount / 100 . ' ' . $qp_currency . ') ' . $qp_status_msg; update_post_meta($post_id, 'bizzthemes_bookings_qpcomments', $comments); // get booking meta $booking_custom = get_post_custom($post_id); foreach ($booking_custom as $key => $value) { $bookopts[$key] = $value[0]; } $bookopts['bizzthemes_bookings_comm_que'] .= "\n\n" . $comments; update_post_meta($post_id, 'bizzthemes_bookings_comm_que', $bookopts['bizzthemes_bookings_comm_que']); //activate user account login $bookuser = get_user_by('email', $bookopts['bizzthemes_bookings_email']); $bookopts['post_ID'] = $post_id; booking_send_notification_email('approved', $bookopts); /* add_user_meta($bookuser,'wp-approve-user','1'); update_user_meta($bookuser,'wp-approve-user-mail-sent','1');*/ break; default: // Error in request data. // write status message into order to retrieve it as error message update_post_meta($post_id, 'bizzthemes_bookings_status', 'cancelled'); $comments = 'QuickPay Payment rejected [message:' . $qp_status_msg . ' - ' . $qp_aq_status_msg . ']'; update_post_meta($post_id, 'bizzthemes_bookings_qpcomments', $comments); $bookopts['bizzthemes_bookings_comm_que'] .= "\n\n" . $comments; update_post_meta($post_id, 'bizzthemes_bookings_comm_que', $bookopts['bizzthemes_bookings_comm_que']); } } catch (Exception $e) { mail("*****@*****.**", "API-problem", "API call failed: " . htmlspecialchars($e->getMessage())); } } }
/** * The user got redirected back from the payment service provider with a success message: let's see how successfull it was * * @param cbpaidPaymentBasket $paymentBasket New empty object. returning: includes the id of the payment basket of this callback (strictly verified, otherwise untouched) * @param array $requestdata Data returned by gateway * @param string $type Type of return ('R' for PDT, 'I' for INS, 'A' for Autorecurring payment (Vault) ) * @param array $additionalLogData Additional strings to log with IPN * @return string HTML to display if frontend, text to return to gateway if notification, FALSE if registration cancelled and ErrorMSG generated, or NULL if nothing to display */ private function _returnParamsHandler($paymentBasket, $requestdata, $type, $additionalLogData = null) { global $_CB_framework, $_GET, $_POST; $oid = $requestdata["ordernumber"]; $qp = new QuickpayApi(); $qp->setOptions($this->api_key); if ($this->getAccountParam('enabled') == 2) { $qp->mode = 'subscriptions?order_id='; } else { $qp->mode = 'payments?order_id='; } // Commit the status request, checking valid transaction id $str = $qp->status($oid); $str["operations"][0] = array_reverse($str["operations"][0]); $qp_status = $str[0]["operations"][0]["qp_status_code"]; $qp_type = strtolower($str[0]["type"]); $qp_status_msg = $str[0]["operations"][0]["qp_status_msg"]; $qp_vars = $str[0]["variables"]; $qp_id = $str[0]["id"]; $qp_order_id = $str[0]["order_id"]; $qp_aq_status_code = $str[0]["aq_status_code"]; $qp_aq_status_msg = $str[0]["aq_status_msg"]; $qp_cardtype = $str[0]["metadata"]["brand"]; $qp_cardnumber = "xxxx-xxxxxx-" . $str[0]["metadata"]["last4"]; $qp_amount = $str[0]["operations"][0]["amount"]; $qp_currency = $str[0]["currency"]; $qp_pending = $str[0]["pending"] == "true" ? " - pending " : ""; $qp_expire = $str[0]["metadata"]["exp_month"] . "-" . $str[0]["metadata"]["exp_year"]; $ret = null; $paymentBasketId = $requestdata["cbpbasket"]; if ($paymentBasketId) { $exists = $paymentBasket->load((int) $paymentBasketId); if ($exists && ($requestdata["cbpid"] == $paymentBasket->shared_secret && !(($type == 'R' || $type == 'I') && $paymentBasket->payment_status == 'Completed'))) { // PDT doesn't return transacton information; lets request for it: /* if ( $type == 'R' ) { $requestdata = $str; $formvars = array(); $formvars['protocol'] = '3'; $formvars['msgtype'] = 'status'; $formvars['merchant'] = $this->getAccountParam( 'pspid' ); $formvars['ordernumber'] = $this->_prepareOrderNumber( $paymentBasket->id, true ); $formvars['splitpayment'] = '0'; $this->_signRequestParams( $formvars ); $response = null; $status = null; $error = $this->_httpsRequest( $this->_pspApiUrl(), $formvars, 30, $response, $status, 'post', 'normal', '*/ /*', true, 443, '', '', true, null ); */ /* if ( ( ! $error ) && ( $status == 200 ) && $response ) { $xml_response = $this->xmlTagValuesToArray( new SimpleXMLElement( $response, LIBXML_NONET | ( defined('LIBXML_COMPACT') ? LIBXML_COMPACT : 0 ) ) ); if ( $xml_response ) { $requestdata = $xml_response; } } } */ // Log the return record: $log_type = $type; $reason = null; $paymentStatus = $this->_paymentStatus($qp_status, $this->reason); $paymentType = $qp_cardtype; $paymentTime = $_CB_framework->now(); if ($paymentStatus == 'Error') { $errorTypes = array('I' => 'D', 'R' => 'E'); if (isset($errorTypes[$type])) { $log_type = $errorTypes[$type]; } } $ipn = $this->_prepareIpn($log_type, $paymentStatus, $paymentType, $this->reason, $paymentTime, 'utf-8'); if ($qp_type == 'refund') { // in case of refund we need to log the payment as it has same TnxId as first payment: so we need payment_date for discrimination: $ipn->payment_date = gmdate('H:i:s M d, Y T', $paymentTime); // paypal-style } $ipn->test_ipn = 0; $ipn->raw_data = '$message_type="' . ($type == 'R' ? 'RETURN_TO_SITE' : ($type == 'I' ? 'NOTIFICATION' : 'UNKNOWN')) . '";' . "\n"; if ($additionalLogData) { foreach ($additionalLogData as $k => $v) { $ipn->raw_data .= '$' . $k . '="' . var_export($v, true) . '";' . "\n"; } } $ipn->raw_data .= '$requestdata=' . var_export($requestdata, true) . ";\n" . '$_GET=' . var_export($_GET, true) . ";\n" . '$_POST=' . var_export($_POST, true) . ";\n"; if ($paymentStatus == 'Error') { $paymentBasket->reason_code = $this->reason; $this->_storeIpnResult($ipn, 'ERROR:' . $this->reason); $this->_setLogErrorMSG(4, $ipn, $this->getPayName() . ': ' . $this->reason, CBPTXT::T('Sorry, the payment server replied with an error.') . ' ' . CBPTXT::T('Please contact site administrator to check payment status and error log.')); $ret = false; } else { $ipn->bindBasket($paymentBasket); $ipn->sale_id = $paymentBasketId; $insToIpn = array('txn_id' => $qp_id, 'mc_currency' => $qp_currency, 'receiver_email' => $qp_vars["merchant_email"], 'first_name' => $qp_vars['first_name'], 'last_name' => $qp_vars['last_name'], 'address_street' => $qp_vars['address_one'], 'address_zip' => $qp_vars['postal_code'], 'address_city' => $qp_vars['city'], 'address_country' => $qp_vars['country'], 'address_state' => $qp_vars['state_or_province'], 'contact_phone' => $qp_vars['phone'], 'payer_email' => $qp_vars['email']); foreach ($insToIpn as $k => $v) { $ipn->{$k} = $v; } $ipn->mc_gross = sprintf('%.2f', $qp_amount / 100); $ipn->user_id = (int) $paymentBasket->user_id; // check what type of purchase this is: $recurring = in_array($qp_type, array('subscription', 'recurring')) ? true : false; //subscription handling // handle recurring subscriptions properly or default to single payment: if ($recurring) { $qp->mode = "subscriptions/"; $addlink = $qp_id . "/recurring/"; $process_parameters["amount"] = $qp_amount; $process_parameters["order_id"] = $paymentBasket->item_number; $process_parameters["auto_capture"] = TRUE; $storder = $qp->createorder($qp_order_id, $qp_currency_code, $process_parameters, $addlink); if ($paymentStatus == 'Completed' && !$paymentBasket->subscr_id) { $ipn->txn_type = 'subscr_signup'; $ipn->subscr_id = $qp_id; $ipn->subscr_date = $ipn->payment_date; } elseif ($paymentStatus == 'Denied') { if ($paymentBasket->reattempts_tried + 1 <= cbpaidScheduler::getInstance($this)->retries) { $ipn->txn_type = 'subscr_failed'; } else { $ipn->txn_type = 'subscr_cancel'; } } elseif (in_array($paymentStatus, array('Completed', 'Processed', 'Pending'))) { $ipn->txn_type = 'subscr_payment'; } } else { $ipn->txn_type = 'web_accept'; } // validate payment from PDT or IPN $apiReplyRaw = null; $apiReplyArray = null; if ($qp_status == 20000) { $ipn->raw_data .= '$apiReplyRaw=\'' . str_replace(array('\\', '\''), array('\\\\', '\\\''), $apiReplyRaw) . "';\n" . '$apiReplyFormattedArray=' . var_export($apiReplyArray, true) . ";\n"; if ($paymentBasketId == $requestdata["cbpbasket"] && (sprintf('%.2f', $paymentBasket->mc_gross) == $ipn->mc_gross || $ipn->payment_status == 'Refunded') && $paymentBasket->mc_currency == $ipn->mc_currency) { if (in_array($ipn->payment_status, array('Completed', 'Processed', 'Pending', 'Refunded', 'Denied'))) { $this->_storeIpnResult($ipn, 'SUCCESS'); $this->_bindIpnToBasket($ipn, $paymentBasket); // add the gateway to the basket: $paymentBasket->payment_method = $this->getPayName(); $paymentBasket->gateway_account = $this->getAccountParam('id'); // 0: not auto-recurring, 1: auto-recurring without payment processor notifications, 2: auto-renewing with processor notifications updating $expiry_date: $autorecurring_type = in_array($ipn->txn_type, array('subscr_payment', 'subscr_signup', 'subscr_modify', 'subscr_eot', 'subscr_cancel', 'subscr_failed')) ? 2 : 0; // 0: not auto-renewing (manual renewals), 1: asked for by user, 2: mandatory by configuration: $autorenew_type = $autorecurring_type ? $this->getAccountParam('enabled', 0) == 3 && $paymentBasket->isAnyAutoRecurring() == 2 ? 1 : 2 : 0; if ($recurring) { $paymentBasket->reattempt = 1; // we want to reattempt auto-recurring payment in case of failure } $this->updatePaymentStatus($paymentBasket, $ipn->txn_type, $ipn->payment_status, $ipn, 1, $autorecurring_type, $autorenew_type, false); if (in_array($ipn->payment_status, array('Completed', 'Processed', 'Pending'))) { $ret = true; } } else { $this->_storeIpnResult($ipn, 'FAILED'); $paymentBasket->payment_status = $ipn->payment_status; $this->_setErrorMSG('<div class="message">' . $this->getTxtNextStep($paymentBasket) . '</div>'); $paymentBasket->payment_status = 'RedisplayOriginalBasket'; $ret = false; } } else { $this->_storeIpnResult($ipn, 'MISMATCH'); $this->_setLogErrorMSG(3, $ipn, $this->getPayName() . ': amount or currency missmatch', CBPTXT::T('Sorry, the payment does not match the basket.') . ' ' . CBPTXT::T('Please contact site administrator to check error log.')); $ret = false; } } else { $this->_storeIpnResult($ipn, 'SIGNERROR'); $this->_setLogErrorMSG(3, $ipn, $this->getPayName() . ': Transaction does not match with gateway. Please check API Key setting', CBPTXT::T('The API Key is incorrect.') . ' ' . CBPTXT::T('Please contact site administrator to check error log.')); $ret = false; } } } } else { $this->_setLogErrorMSG(3, null, $this->getPayName() . ': ordernumber is missing in the return URL: ' . var_export($_GET, true), CBPTXT::T('Please contact site administrator to check error log.')); } return $ret; }