$this->load->model('payment/pp_express');
$this->load->model('account/recurring');
$request = 'cmd=_notify-validate';
foreach ($_POST as $key => $value) {
$request .= '&' . $key . '=' . urlencode(stripslashes($value));
}
if ($this->config->get('pp_express_test') == 1) {
$curl = curl_init('https://www.sandbox.paypal.com/cgi-bin/webscr');
} else {
$curl = curl_init('https://www.paypal.com/cgi-bin/webscr');
}
curl_setopt($curl, CURLOPT_POST, true);
curl_setopt($curl, CURLOPT_POSTFIELDS, $request);
curl_setopt($curl, CURLOPT_RETURNTRANSFER, true);
curl_setopt($curl, CURLOPT_HEADER, false);
curl_setopt($curl, CURLOPT_TIMEOUT, 30);
curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, false);
$response = trim(curl_exec($curl));
if (!$response) {
$this->model_payment_pp_express->log(array('error' => curl_error($curl),'error_no' => curl_errno($curl)), 'Curl failed');
}
$this->model_payment_pp_express->log(array('request' => $request,'response' => $response), 'IPN data');
if ( (string)$response == "VERIFIED" ) {
if($this->config->get('pp_express_debug') == 1) {
$this->log->write((isset($this->request->post['transaction_entity']) ? $this->request->post['transaction_entity'] : ''));
}
if(isset($this->request->post['txn_id'])) {
$transaction = $this->model_payment_pp_express->getTransactionRow($this->request->post['txn_id']);
} else {
$transaction = false;
}
if(isset($this->request->post['parent_txn_id'])) {
$parent_transaction = $this->model_payment_pp_express->getTransactionRow($this->request->post['parent_txn_id']);
} else {
$parent_transaction = false;
}
if($transaction) {
//transaction exists, check for cleared payment or updates etc
if($this->config->get('pp_express_debug') == 1) {
$this->log->write('Transaction exists');
}
//if the transaction is pending but the new status is completed
if($transaction['payment_status'] != $this->request->post['payment_status']) {
$this->db->query("UPDATE `" . DB_PREFIX . "paypal_order_transaction` SET `payment_status` = '" . $this->request->post['payment_status'] . "' WHERE `transaction_id` = '" . $this->db->escape($transaction['transaction_id']) . "' LIMIT 1");
}elseif($transaction['payment_status'] == 'Pending' && ($transaction['pending_reason'] != $this->request->post['pending_reason'])) {
//payment is still pending but the pending reason has changed, update it.
$this->db->query("UPDATE `" . DB_PREFIX . "paypal_order_transaction` SET `pending_reason` = '" . $this->request->post['pending_reason'] . "' WHERE `transaction_id` = '" . $this->db->escape($transaction['transaction_id']) . "' LIMIT 1");
}
} else {
if($this->config->get('pp_express_debug') == 1) {
$this->log->write('Transaction does not exist');
}
if($parent_transaction) {
//parent transaction exists
if($this->config->get('pp_express_debug') == 1) {
$this->log->write('Parent transaction exists');
}
//insert new related transaction
$transaction = array(
'paypal_order_id' => $parent_transaction['paypal_order_id'],
'transaction_id' => $this->request->post['txn_id'],
'parent_transaction_id' => $this->request->post['parent_txn_id'],
'note' => '',
'msgsubid' => '',
'receipt_id' => (isset($this->request->post['receipt_id']) ? $this->request->post['receipt_id'] : ''),
'payment_type' => (isset($this->request->post['payment_type']) ? $this->request->post['payment_type'] : ''),
'payment_status' => (isset($this->request->post['payment_status']) ? $this->request->post['payment_status'] : ''),
'pending_reason' => (isset($this->request->post['pending_reason']) ? $this->request->post['pending_reason'] : ''),
'amount' => $this->request->post['mc_gross'],
'debug_data' => json_encode($this->request->post),
'transaction_entity' => (isset($this->request->post['transaction_entity']) ? $this->request->post['transaction_entity'] : ''),
);
$this->model_payment_pp_express->addTransaction($transaction);
/**
* If there has been a refund, log this against the parent transaction.
*/
if(isset($this->request->post['payment_status']) && $this->request->post['payment_status'] == 'Refunded') {
if(($this->request->post['mc_gross'] * -1) == $parent_transaction['amount']) {
$this->db->query("UPDATE `" . DB_PREFIX . "paypal_order_transaction` SET `payment_status` = 'Refunded' WHERE `transaction_id` = '" . $this->db->escape($parent_transaction['transaction_id']) . "' LIMIT 1");
} else {
$this->db->query("UPDATE `" . DB_PREFIX . "paypal_order_transaction` SET `payment_status` = 'Partially-Refunded' WHERE `transaction_id` = '" . $this->db->escape($parent_transaction['transaction_id']) . "' LIMIT 1");
}
}
/**
* If the capture payment is now complete
*/
if(isset($this->request->post['auth_status']) && $this->request->post['auth_status'] == 'Completed' && $parent_transaction['payment_status'] == 'Pending') {
$captured = number_format($this->model_payment_pp_express->totalCaptured($parent_transaction['paypal_order_id']), 2);
$refunded = number_format($this->model_payment_pp_express->totalRefundedOrder($parent_transaction['paypal_order_id']), 2);
$remaining = number_format($parent_transaction['amount'] - $captured + $refunded, 2);
if($this->config->get('pp_express_debug') == 1) {
$this->log->write('Captured: '.$captured);
$this->log->write('Refunded: '.$refunded);
$this->log->write('Remaining: '.$remaining);
}
if($remaining > 0.00) {
$transaction = array(
'paypal_order_id' => $parent_transaction['paypal_order_id'],
'transaction_id' => '',
'parent_transaction_id' => $this->request->post['parent_txn_id'],
'note' => '',
'msgsubid' => '',
'receipt_id' => '',
'payment_type' => '',
'payment_status' => 'Void',
'pending_reason' => '',
'amount' => '',
'debug_data' => 'Voided after capture',
'transaction_entity' => 'auth'
);
$this->model_payment_pp_express->addTransaction($transaction);
}
$this->model_payment_pp_express->updateOrder('Complete', $parent_transaction['order_id']);
}
} else {
//parent transaction doesn't exists, need to investigate?
if($this->config->get('pp_express_debug') == 1) {
$this->log->write('Parent transaction not found');
}
}
}
/*
* Subscription payments
*
* profile ID should always exist if its a recurring payment transaction.
*
* also the reference will match a recurring payment ID
*/
if (isset($this->request->post['txn_type'])) {
//payment
if ($this->request->post['txn_type'] == 'recurring_payment') {
$profile = $this->model_account_recurring->getProfileByRef($this->request->post['recurring_payment_id']);
if ($profile != false) {
$this->db->query("INSERT INTO `" . DB_PREFIX . "order_recurring_transaction` SET `order_recurring_id` = '" . (int)$profile['order_recurring_id'] . "', `created` = NOW(), `amount` = '" . (float)$this->request->post['amount'] . "', `type` = '1'");
//as there was a payment the profile is active, ensure it is set to active (may be been suspended before)
if ($profile['status'] != 1) {
$this->db->query("UPDATE `" . DB_PREFIX . "order_recurring` SET `status` = 2 WHERE `order_recurring_id` = '" . (int)$profile['order_recurring_id'] . "'");
}
}
}
//suspend
if ($this->request->post['txn_type'] == 'recurring_payment_suspended') {
$profile = $this->model_account_recurring->getProfileByRef($this->request->post['recurring_payment_id']);
if ($profile != false) {
$this->db->query("INSERT INTO `" . DB_PREFIX . "order_recurring_transaction` SET `order_recurring_id` = '" . (int)$profile['order_recurring_id'] . "', `created` = NOW(), `type` = '6'");
$this->db->query("UPDATE `" . DB_PREFIX . "order_recurring` SET `status` = 3 WHERE `order_recurring_id` = '" . (int)$profile['order_recurring_id'] . "' LIMIT 1");
}
}
//suspend due to max failed
if ($this->request->post['txn_type'] == 'recurring_payment_suspended_due_to_max_failed_payment') {
$profile = $this->model_account_recurring->getProfileByRef($this->request->post['recurring_payment_id']);
if ($profile != false) {
$this->db->query("INSERT INTO `" . DB_PREFIX . "order_recurring_transaction` SET `order_recurring_id` = '" . (int)$profile['order_recurring_id'] . "', `created` = NOW(), `type` = '7'");
$this->db->query("UPDATE `" . DB_PREFIX . "order_recurring` SET `status` = 3 WHERE `order_recurring_id` = '" . (int)$profile['order_recurring_id'] . "' LIMIT 1");
}
}
//payment failed
if ($this->request->post['txn_type'] == 'recurring_payment_failed') {
$profile = $this->model_account_recurring->getProfileByRef($this->request->post['recurring_payment_id']);
if ($profile != false) {
$this->db->query("INSERT INTO `" . DB_PREFIX . "order_recurring_transaction` SET `order_recurring_id` = '" . (int)$profile['order_recurring_id'] . "', `created` = NOW(), `type` = '4'");
}
}
//outstanding payment failed
if ($this->request->post['txn_type'] == 'recurring_payment_outstanding_payment_failed') {
$profile = $this->model_account_recurring->getProfileByRef($this->request->post['recurring_payment_id']);
if ($profile != false) {
$this->db->query("INSERT INTO `" . DB_PREFIX . "order_recurring_transaction` SET `order_recurring_id` = '" . (int)$profile['order_recurring_id'] . "', `created` = NOW(), `type` = '8'");
}
}
//outstanding payment
if ($this->request->post['txn_type'] == 'recurring_payment_outstanding_payment') {
$profile = $this->model_account_recurring->getProfileByRef($this->request->post['recurring_payment_id']);
if ($profile != false) {
$this->db->query("INSERT INTO `" . DB_PREFIX . "order_recurring_transaction` SET `order_recurring_id` = '" . (int)$profile['order_recurring_id'] . "', `created` = NOW(), `amount` = '" . (float)$this->request->post['amount'] . "', `type` = '2'");
//as there was a payment the profile is active, ensure it is set to active (may be been suspended before)
if ($profile['status'] != 1) {
$this->db->query("UPDATE `" . DB_PREFIX . "order_recurring` SET `status` = 2 WHERE `order_recurring_id` = '" . (int)$profile['order_recurring_id'] . "'");
}
}
}
//created
if ($this->request->post['txn_type'] == 'recurring_payment_profile_created') {
$profile = $this->model_account_recurring->getProfileByRef($this->request->post['recurring_payment_id']);
if ($profile != false) {
$this->db->query("INSERT INTO `" . DB_PREFIX . "order_recurring_transaction` SET `order_recurring_id` = '" . (int)$profile['order_recurring_id'] . "', `created` = NOW(), `type` = '0'");
if ($profile['status'] != 1) {
$this->db->query("UPDATE `" . DB_PREFIX . "order_recurring` SET `status` = 2 WHERE `order_recurring_id` = '" . (int)$profile['order_recurring_id'] . "'");
}
}
}
//cancelled
if ($this->request->post['txn_type'] == 'recurring_payment_profile_cancel') {
$profile = $this->model_account_recurring->getProfileByRef($this->request->post['recurring_payment_id']);
if ($profile != false && $profile['status'] != 3) {
$this->db->query("INSERT INTO `" . DB_PREFIX . "order_recurring_transaction` SET `order_recurring_id` = '" . (int)$profile['order_recurring_id'] . "', `created` = NOW(), `type` = '5'");
$this->db->query("UPDATE `" . DB_PREFIX . "order_recurring` SET `status` = 4 WHERE `order_recurring_id` = '" . (int)$profile['order_recurring_id'] . "' LIMIT 1");
}
}
//skipped
if ($this->request->post['txn_type'] == 'recurring_payment_skipped') {
$profile = $this->model_account_recurring->getProfileByRef($this->request->post['recurring_payment_id']);
if ($profile != false) {
$this->db->query("INSERT INTO `" . DB_PREFIX . "order_recurring_transaction` SET `order_recurring_id` = '" . (int)$profile['order_recurring_id'] . "', `created` = NOW(), `type` = '3'");
}
}
//expired
if ($this->request->post['txn_type'] == 'recurring_payment_expired') {
$profile = $this->model_account_recurring->getProfileByRef($this->request->post['recurring_payment_id']);
if ($profile != false) {
$this->db->query("INSERT INTO `" . DB_PREFIX . "order_recurring_transaction` SET `order_recurring_id` = '" . (int)$profile['order_recurring_id'] . "', `created` = NOW(), `type` = '9'");
$this->db->query("UPDATE `" . DB_PREFIX . "order_recurring` SET `status` = 5 WHERE `order_recurring_id` = '" . (int)$profile['order_recurring_id'] . "' LIMIT 1");
}
}
}
}elseif( (string)$response == "INVALID" ) {
$this->model_payment_pp_express->log(array('IPN was invalid'), 'IPN fail');
} else {
if($this->config->get('pp_express_debug') == 1) {
$this->log->write('string unknown ');
}
}
header("HTTP/1.1 200 Ok");