shop.balmet.com

Unnamed repository; edit this file 'description' to name the repository.
Log | Files | Refs | README

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 }