amazon_login_pay.php (18648B)
1 <?php 2 class ModelExtensionPaymentAmazonLoginPay extends Model { 3 4 public function install() { 5 $this->db->query(" 6 CREATE TABLE `" . DB_PREFIX . "amazon_login_pay_order` ( 7 `amazon_login_pay_order_id` INT(11) NOT NULL AUTO_INCREMENT, 8 `order_id` int(11) NOT NULL, 9 `amazon_order_reference_id` varchar(255) NOT NULL, 10 `amazon_authorization_id` varchar(255) NOT NULL, 11 `free_shipping` tinyint NOT NULL DEFAULT 0, 12 `date_added` DATETIME NOT NULL, 13 `modified` DATETIME NOT NULL, 14 `capture_status` INT(1) DEFAULT NULL, 15 `cancel_status` INT(1) DEFAULT NULL, 16 `refund_status` INT(1) DEFAULT NULL, 17 `currency_code` CHAR(3) NOT NULL, 18 `total` DECIMAL( 10, 2 ) NOT NULL, 19 KEY `amazon_order_reference_id` (`amazon_order_reference_id`), 20 PRIMARY KEY `amazon_login_pay_order_id` (`amazon_login_pay_order_id`) 21 ) ENGINE=MyISAM DEFAULT CHARSET=utf8 COLLATE=utf8_general_ci; 22 "); 23 24 $this->db->query(" 25 CREATE TABLE `" . DB_PREFIX . "amazon_login_pay_order_total_tax` ( 26 `order_total_id` INT, 27 `code` VARCHAR(255), 28 `tax` DECIMAL(10, 4) NOT NULL, 29 PRIMARY KEY (`order_total_id`) 30 ) ENGINE=MyISAM DEFAULT CHARSET=utf8 COLLATE=utf8_general_ci; 31 "); 32 33 $this->db->query(" 34 CREATE TABLE IF NOT EXISTS `" . DB_PREFIX . "amazon_login_pay_order_transaction` ( 35 `amazon_login_pay_order_transaction_id` INT(11) NOT NULL AUTO_INCREMENT, 36 `amazon_login_pay_order_id` INT(11) NOT NULL, 37 `amazon_authorization_id` varchar(255), 38 `amazon_capture_id` varchar(255), 39 `amazon_refund_id` varchar(255), 40 `date_added` DATETIME NOT NULL, 41 `type` ENUM('authorization', 'capture', 'refund', 'cancel') DEFAULT NULL, 42 `status` ENUM('Open', 'Pending', 'Completed', 'Suspended', 'Declined', 'Closed', 'Canceled') DEFAULT NULL, 43 `amount` DECIMAL( 10, 2 ) NOT NULL, 44 PRIMARY KEY (`amazon_login_pay_order_transaction_id`) 45 ) ENGINE=MyISAM DEFAULT COLLATE=utf8_general_ci; 46 "); 47 } 48 49 public function uninstall() { 50 $this->db->query("DROP TABLE IF EXISTS `" . DB_PREFIX . "amazon_login_pay_order`;"); 51 $this->db->query("DROP TABLE IF EXISTS `" . DB_PREFIX . "amazon_login_pay_order_total_tax`;"); 52 $this->db->query("DROP TABLE IF EXISTS `" . DB_PREFIX . "amazon_login_pay_order_transaction`;"); 53 } 54 55 public function getOrder($order_id) { 56 57 $qry = $this->db->query("SELECT * FROM `" . DB_PREFIX . "amazon_login_pay_order` WHERE `order_id` = '" . (int)$order_id . "' LIMIT 1"); 58 59 if ($qry->num_rows) { 60 $order = $qry->row; 61 $order['transactions'] = $this->getTransactions($order['amazon_login_pay_order_id'], $qry->row['currency_code']); 62 return $order; 63 } else { 64 return false; 65 } 66 } 67 68 public function cancel($amazon_login_pay_order) { 69 $total_captured = $this->getTotalCaptured($amazon_login_pay_order['amazon_login_pay_order_id']); 70 71 if (!empty($amazon_login_pay_order) && $total_captured == 0) { 72 73 $cancel_response = array(); 74 $cancel_paramter_data = array(); 75 76 $cancel_paramter_data['AmazonOrderReferenceId'] = $amazon_login_pay_order['amazon_order_reference_id']; 77 $cancel_details = $this->offAmazon('CancelOrderReference', $cancel_paramter_data); 78 $cancel_details_xml = simplexml_load_string($cancel_details['ResponseBody']); 79 $this->logger($cancel_details_xml); 80 if (isset($cancel_details_xml->Error)) { 81 $cancel_response['status'] = 'Error'; 82 $cancel_response['status_detail'] = (string)$cancel_details_xml->Error->Code . ': ' . (string)$cancel_details_xml->Error->Message; 83 } else { 84 $cancel_response['status'] = 'Completed'; 85 } 86 return $cancel_response; 87 } else { 88 return false; 89 } 90 } 91 92 public function updateCancelStatus($amazon_login_pay_order_id, $status) { 93 $this->db->query("UPDATE `" . DB_PREFIX . "amazon_login_pay_order` SET `cancel_status` = '" . (int)$status . "' WHERE `amazon_login_pay_order_id` = '" . (int)$amazon_login_pay_order_id . "'"); 94 } 95 96 public function capture($amazon_login_pay_order, $amount) { 97 $total_captured = $this->getTotalCaptured($amazon_login_pay_order['amazon_login_pay_order_id']); 98 99 if (!empty($amazon_login_pay_order) && $amazon_login_pay_order['capture_status'] == 0 && ($total_captured + $amount <= $amazon_login_pay_order['total'])) { 100 if (count($amazon_login_pay_order['transactions']) != 1) { 101 $amazon_authorization = $this->authorize($amazon_login_pay_order, $amount); 102 if (isset($amazon_authorization['AmazonAuthorizationId'])) { 103 $amazon_authorization_id = $amazon_authorization['AmazonAuthorizationId']; 104 } else { 105 return $amazon_authorization; 106 } 107 } else { 108 $amazon_authorization_id = $amazon_login_pay_order['amazon_authorization_id']; 109 } 110 111 $capture_paramter_data = array(); 112 $capture_paramter_data['AmazonOrderReferenceId'] = $amazon_login_pay_order['amazon_order_reference_id']; 113 $capture_paramter_data['AmazonAuthorizationId'] = $amazon_authorization_id; 114 $capture_paramter_data['CaptureAmount.Amount'] = $amount; 115 $capture_paramter_data['CaptureAmount.CurrencyCode'] = $amazon_login_pay_order['currency_code']; 116 $capture_paramter_data['CaptureReferenceId'] = 'capture_' . mt_rand(); 117 $capture_paramter_data['TransactionTimeout'] = 0; 118 $capture_details = $this->offAmazon('Capture', $capture_paramter_data); 119 120 $capture_response = $this->validateResponse('Capture', $capture_details); 121 $capture_response['AmazonAuthorizationId'] = $amazon_authorization_id; 122 return $capture_response; 123 } else { 124 return false; 125 } 126 } 127 128 private function authorize($amazon_login_pay_order, $amount) { 129 $authorize_paramter_data = array(); 130 $authorize_paramter_data['AmazonOrderReferenceId'] = $amazon_login_pay_order['amazon_order_reference_id']; 131 $authorize_paramter_data['AuthorizationAmount.Amount'] = $amount; 132 $authorize_paramter_data['AuthorizationAmount.CurrencyCode'] = $amazon_login_pay_order['currency_code']; 133 $authorize_paramter_data['AuthorizationReferenceId'] = 'auth_' . mt_rand(); 134 $authorize_paramter_data['TransactionTimeout'] = 0; 135 $authorize_details = $this->offAmazon('Authorize', $authorize_paramter_data); 136 137 return $this->validateResponse('Authorize', $authorize_details); 138 } 139 140 public function closeOrderRef($amazon_order_reference_id) { 141 $close_paramter_data = array(); 142 $close_paramter_data['AmazonOrderReferenceId'] = $amazon_order_reference_id; 143 $this->offAmazon('CloseOrderReference', $close_paramter_data); 144 $close_details = $this->offAmazon('CloseOrderReference', $close_paramter_data); 145 $this->logger($close_details); 146 } 147 148 public function updateCaptureStatus($amazon_login_pay_order_id, $status) { 149 $this->db->query("UPDATE `" . DB_PREFIX . "amazon_login_pay_order` SET `capture_status` = '" . (int)$status . "' WHERE `amazon_login_pay_order_id` = '" . (int)$amazon_login_pay_order_id . "'"); 150 } 151 152 public function refund($amazon_login_pay_order, $amount) { 153 if (!empty($amazon_login_pay_order) && $amazon_login_pay_order['refund_status'] != 1) { 154 $amazon_captures_remaining = $this->getUnCaptured($amazon_login_pay_order['amazon_login_pay_order_id']); 155 156 $refund_response = array(); 157 $i = 0; 158 $count = count($amazon_captures_remaining); 159 for ($amount; $amount > 0 && $count > $i; $amount -= $amazon_captures_remaining[$i++]['capture_remaining']) { 160 $refund_amount = $amount; 161 if ($amazon_captures_remaining[$i]['capture_remaining'] <= $amount) { 162 $refund_amount = $amazon_captures_remaining[$i]['capture_remaining']; 163 } 164 165 $refund_paramter_data = array(); 166 $refund_paramter_data['AmazonOrderReferenceId'] = $amazon_login_pay_order['amazon_order_reference_id']; 167 $refund_paramter_data['AmazonCaptureId'] = $amazon_captures_remaining[$i]['amazon_capture_id']; 168 $refund_paramter_data['RefundAmount.Amount'] = $refund_amount; 169 $refund_paramter_data['RefundAmount.CurrencyCode'] = $amazon_login_pay_order['currency_code']; 170 $refund_paramter_data['RefundReferenceId'] = 'refund_' . mt_rand(); 171 $refund_paramter_data['TransactionTimeout'] = 0; 172 $refund_details = $this->offAmazon('Refund', $refund_paramter_data); 173 $refund_response[$i] = $this->validateResponse('Refund', $refund_details); 174 $refund_response[$i]['amazon_authorization_id'] = $amazon_captures_remaining[$i]['amazon_authorization_id']; 175 $refund_response[$i]['amazon_capture_id'] = $amazon_captures_remaining[$i]['amazon_capture_id']; 176 $refund_response[$i]['amount'] = $refund_amount; 177 } 178 179 return $refund_response; 180 } else { 181 return false; 182 } 183 } 184 185 public function getUnCaptured($amazon_login_pay_order_id) { 186 $qry = $this->db->query("SELECT * FROM `" . DB_PREFIX . "amazon_login_pay_order_transaction` WHERE (`type` = 'refund' OR `type` = 'capture') AND `amazon_login_pay_order_id` = '" . (int)$amazon_login_pay_order_id . "' ORDER BY `date_added`"); 187 $uncaptured = array(); 188 foreach ($qry->rows as $row) { 189 $uncaptured[$row['amazon_capture_id']]['amazon_authorization_id'] = $row['amazon_authorization_id']; 190 $uncaptured[$row['amazon_capture_id']]['amazon_capture_id'] = $row['amazon_capture_id']; 191 if (isset($uncaptured[$row['amazon_capture_id']]['capture_remaining'])) { 192 $uncaptured[$row['amazon_capture_id']]['capture_remaining'] += $row['amount']; 193 } else { 194 $uncaptured[$row['amazon_capture_id']]['capture_remaining'] = $row['amount']; 195 } 196 197 if ($uncaptured[$row['amazon_capture_id']]['capture_remaining'] == 0) { 198 unset($uncaptured[$row['amazon_capture_id']]); 199 } 200 } 201 return array_values($uncaptured); 202 } 203 204 public function updateRefundStatus($amazon_login_pay_order_id, $status) { 205 $this->db->query("UPDATE `" . DB_PREFIX . "amazon_login_pay_order` SET `refund_status` = '" . (int)$status . "' WHERE `amazon_login_pay_order_id` = '" . (int)$amazon_login_pay_order_id . "'"); 206 } 207 208 public function getCapturesRemaining($amazon_login_pay_order_id) { 209 $query = $this->db->query("SELECT * FROM `" . DB_PREFIX . "amazon_login_pay_order_transaction` WHERE `amazon_login_pay_order_id` = '" . (int)$amazon_login_pay_order_id . "' AND capture_remaining != '0' ORDER BY `date_added`"); 210 if ($query->num_rows) { 211 return $query->rows; 212 } else { 213 return false; 214 } 215 } 216 217 private function getTransactions($amazon_login_pay_order_id, $currency_code) { 218 $query = $this->db->query("SELECT * FROM `" . DB_PREFIX . "amazon_login_pay_order_transaction` WHERE `amazon_login_pay_order_id` = '" . (int)$amazon_login_pay_order_id . "'"); 219 220 $transactions = array(); 221 if ($query->num_rows) { 222 foreach ($query->rows as $row) { 223 $row['amount'] = $this->currency->format($row['amount'], $currency_code, true, true); 224 $transactions[] = $row; 225 } 226 return $transactions; 227 } else { 228 return false; 229 } 230 } 231 232 public function addTransaction($amazon_login_pay_order_id, $type, $status, $total, $amazon_authorization_id = null, $amazon_capture_id = null, $amazon_refund_id = null) { 233 $this->db->query("INSERT INTO `" . DB_PREFIX . "amazon_login_pay_order_transaction` SET `amazon_login_pay_order_id` = '" . (int)$amazon_login_pay_order_id . "',`amazon_authorization_id` = '" . $this->db->escape($amazon_authorization_id) . "',`amazon_capture_id` = '" . $this->db->escape($amazon_capture_id) . "',`amazon_refund_id` = '" . $this->db->escape($amazon_refund_id) . "', `date_added` = now(), `type` = '" . $this->db->escape($type) . "', `amount` = '" . (double)$total . "', `status` = '" . $this->db->escape($status) . "'"); 234 } 235 236 public function getTotalCaptured($amazon_login_pay_order_id) { 237 $query = $this->db->query("SELECT SUM(`amount`) AS `total` FROM `" . DB_PREFIX . "amazon_login_pay_order_transaction` WHERE `amazon_login_pay_order_id` = '" . (int)$amazon_login_pay_order_id . "' AND (`type` = 'capture' OR `type` = 'refund') AND (`status` = 'Completed' OR `status` = 'Closed')"); 238 239 return (double)$query->row['total']; 240 } 241 242 public function getTotalRefunded($amazon_login_pay_order_id) { 243 $query = $this->db->query("SELECT SUM(`amount`) AS `total` FROM `" . DB_PREFIX . "amazon_login_pay_order_transaction` WHERE `amazon_login_pay_order_id` = '" . (int)$amazon_login_pay_order_id . "' AND 'refund'"); 244 245 return (double)$query->row['total']; 246 } 247 248 public function validateDetails($data) { 249 $validate_paramter_data = array(); 250 $validate_paramter_data['AWSAccessKeyId'] = $data['payment_amazon_login_pay_access_key']; 251 $validate_paramter_data['SellerId'] = $data['payment_amazon_login_pay_merchant_id']; 252 $validate_paramter_data['AmazonOrderReferenceId'] = 'validate details'; 253 $validate_details = $this->offAmazon('GetOrderReferenceDetails', $validate_paramter_data); 254 $validate_response = $this->validateResponse('GetOrderReferenceDetails', $validate_details); 255 if($validate_response['error_code'] && $validate_response['error_code'] != 'InvalidOrderReferenceId'){ 256 return $validate_response; 257 } 258 } 259 260 public function offAmazon($Action, $parameter_data, $post_data = array()) { 261 if(!empty($post_data)){ 262 $merchant_id = $post_data['payment_amazon_login_pay_merchant_id']; 263 $access_key = $post_data['payment_amazon_login_pay_access_key']; 264 $access_secret = $post_data['payment_amazon_login_pay_access_secret']; 265 $test = $post_data['payment_amazon_login_pay_test']; 266 $payment_region = $post_data['payment_amazon_login_pay_payment_region']; 267 } else { 268 $merchant_id = $this->config->get('payment_amazon_login_pay_merchant_id'); 269 $access_key = $this->config->get('payment_amazon_login_pay_access_key'); 270 $access_secret = $this->config->get('payment_amazon_login_pay_access_secret'); 271 $test = $this->config->get('payment_amazon_login_pay_test'); 272 $payment_region = $this->config->get('payment_amazon_login_pay_payment_region'); 273 274 } 275 276 if ($test == 'sandbox') { 277 if ($payment_region == 'USD') { 278 $url = 'https://mws.amazonservices.com/OffAmazonPayments_Sandbox/2013-01-01/'; 279 } else { 280 $url = 'https://mws-eu.amazonservices.com/OffAmazonPayments_Sandbox/2013-01-01/'; 281 } 282 } else { 283 if ($payment_region == 'USD') { 284 $url = 'https://mws.amazonservices.com/OffAmazonPayments/2013-01-01/'; 285 } else { 286 $url = 'https://mws-eu.amazonservices.com/OffAmazonPayments/2013-01-01/'; 287 } 288 } 289 290 $parameters = array(); 291 $parameters['AWSAccessKeyId'] = $access_key; 292 $parameters['Action'] = $Action; 293 $parameters['SellerId'] = $merchant_id; 294 $parameters['SignatureMethod'] = 'HmacSHA256'; 295 $parameters['SignatureVersion'] = 2; 296 $parameters['Timestamp'] = date('c', time()); 297 $parameters['Version'] = '2013-01-01'; 298 foreach ($parameter_data as $k => $v) { 299 $parameters[$k] = $v; 300 } 301 302 $query = $this->calculateStringToSignV2($parameters, $url); 303 304 $parameters['Signature'] = base64_encode(hash_hmac('sha256', $query, $access_secret, true)); 305 306 return $this->sendCurl($url, $parameters); 307 } 308 309 private function validateResponse($action, $details) { 310 $details_xml = simplexml_load_string($details['ResponseBody']); 311 $this->logger($details_xml); 312 switch ($action) { 313 case 'Authorize': 314 $result = 'AuthorizeResult'; 315 $details = 'AuthorizationDetails'; 316 $status = 'AuthorizationStatus'; 317 $amazon_id = 'AmazonAuthorizationId'; 318 break; 319 case 'Capture': 320 $result = 'CaptureResult'; 321 $details = 'CaptureDetails'; 322 $status = 'CaptureStatus'; 323 $amazon_id = 'AmazonCaptureId'; 324 break; 325 case 'Refund': 326 $result = 'RefundResult'; 327 $details = 'RefundDetails'; 328 $status = 'RefundStatus'; 329 $amazon_id = 'AmazonRefundId'; 330 } 331 332 $details_xml->registerXPathNamespace('m', 'http://mws.amazonservices.com/schema/OffAmazonPayments/2013-01-01'); 333 $error_set = $details_xml->xpath('//m:ReasonCode'); 334 335 if (isset($details_xml->Error)) { 336 $response['status'] = 'Error'; 337 $response['error_code'] = (string)$details_xml->Error->Code; 338 $response['status_detail'] = (string)$details_xml->Error->Code . ': ' . (string)$details_xml->Error->Message; 339 } elseif (!empty($error_set)) { 340 $response['status'] = (string)$details_xml->$result->$details->$status->State; 341 $response['status_detail'] = (string)$details_xml->$result->$details->$status->ReasonCode; 342 } else { 343 $response['status'] = (string)$details_xml->$result->$details->$status->State; 344 $response[$amazon_id] = (string)$details_xml->$result->$details->$amazon_id; 345 } 346 347 return $response; 348 } 349 350 public function sendCurl($url, $parameters) { 351 $query = $this->getParametersAsString($parameters); 352 353 $curl = curl_init($url); 354 355 curl_setopt($curl, CURLOPT_URL, $url); 356 curl_setopt($curl, CURLOPT_PORT, 443); 357 curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, true); 358 curl_setopt($curl, CURLOPT_SSL_VERIFYHOST, 2); 359 curl_setopt($curl, CURLOPT_USERAGENT, $this->request->server['HTTP_USER_AGENT']); 360 curl_setopt($curl, CURLOPT_POST, true); 361 curl_setopt($curl, CURLOPT_POSTFIELDS, $query); 362 curl_setopt($curl, CURLOPT_HEADER, true); 363 curl_setopt($curl, CURLOPT_RETURNTRANSFER, true); 364 365 $response = curl_exec($curl); 366 curl_close($curl); 367 368 list($other, $responseBody) = explode("\r\n\r\n", $response, 2); 369 $other = preg_split("/\r\n|\n|\r/", $other); 370 371 list($protocol, $code, $text) = explode(' ', trim(array_shift($other)), 3); 372 return array('status' => (int)$code, 'ResponseBody' => $responseBody); 373 } 374 375 private function getParametersAsString(array $parameters) { 376 $queryParameters = array(); 377 foreach ($parameters as $key => $value) { 378 $queryParameters[] = $key . '=' . $this->urlencode($value); 379 } 380 return implode('&', $queryParameters); 381 } 382 383 private function calculateStringToSignV2(array $parameters, $url) { 384 $data = 'POST'; 385 $data .= "\n"; 386 $endpoint = parse_url($url); 387 $data .= $endpoint['host']; 388 $data .= "\n"; 389 $uri = array_key_exists('path', $endpoint) ? $endpoint['path'] : null; 390 if (!isset($uri)) { 391 $uri = "/"; 392 } 393 $uriencoded = implode("/", array_map(array($this, "urlencode"), explode("/", $uri))); 394 $data .= $uriencoded; 395 $data .= "\n"; 396 uksort($parameters, 'strcmp'); 397 $data .= $this->getParametersAsString($parameters); 398 return $data; 399 } 400 401 private function urlencode($value) { 402 return str_replace('%7E', '~', rawurlencode($value)); 403 } 404 405 public function logger($message) { 406 if ($this->config->get('payment_amazon_login_pay_debug') == 1) { 407 $log = new Log('amazon_login_pay.log'); 408 $backtrace = debug_backtrace(); 409 $log->write('Origin: ' . $backtrace[6]['class'] . '::' . $backtrace[6]['function']); 410 $log->write(print_r($message, 1)); 411 } 412 } 413 }