1<?php
2class ControllerExtensionPaymentSecureTradingWs extends Controller {
3	public function index() {
4		$this->load->model('checkout/order');
5		$this->load->language('extension/payment/securetrading_ws');
6
7		if(!isset($this->session->data['order_id'])) {
8			return false;
9		}
10
11		$order_info = $this->model_checkout_order->getOrder($this->session->data['order_id']);
12
13		if ($order_info) {
14			$data['entry_type'] = $this->language->get('entry_type');
15			$data['entry_number'] = $this->language->get('entry_number');
16			$data['entry_expire_date'] = $this->language->get('entry_expire_date');
17			$data['entry_cvv2'] = $this->language->get('entry_cvv2');
18
19			$data['text_card_details'] = $this->language->get('text_card_details');
20			$data['text_wait'] = $this->language->get('text_wait');
21
22			$data['button_confirm'] = $this->language->get('button_confirm');
23
24			$cards = array(
25				'AMEX' => 'American Express',
26				'VISA' => 'Visa',
27				'DELTA' => 'Visa Debit',
28				'ELECTRON' => 'Visa Electron',
29				'PURCHASING' => 'Visa Purchasing',
30				'VPAY' => 'V Pay',
31				'MASTERCARD' => 'MasterCard',
32				'MASTERCARDDEBIT' => 'MasterCard Debit',
33				'MAESTRO' => 'Maestro',
34				'PAYPAL' => 'PayPal',
35			);
36
37			for ($i = 1; $i <= 12; $i++) {
38				$data['months'][] = array(
39					'text' => strftime('%B', mktime(0, 0, 0, $i, 1, 2000)),
40					'value' => sprintf('%02d', $i)
41				);
42			}
43
44			$today = getdate();
45
46			$data['year_expire'] = array();
47
48			for ($i = $today['year']; $i < $today['year'] + 11; $i++) {
49				$data['year_expire'][] = array(
50					'text' => strftime('%Y', mktime(0, 0, 0, 1, 1, $i)),
51					'value' => strftime('%Y', mktime(0, 0, 0, 1, 1, $i))
52				);
53			}
54
55			$data['cards'] = array();
56
57			foreach ($this->config->get('payment_securetrading_ws_cards_accepted') as $card_type) {
58				$data['cards'][$card_type] = $cards[$card_type];
59			}
60
61			return $this->load->view('extension/payment/securetrading_ws', $data);
62		}
63	}
64
65	public function process() {
66		$this->load->model('checkout/order');
67		$this->load->model('localisation/country');
68		$this->load->model('extension/payment/securetrading_ws');
69		$this->load->language('extension/payment/securetrading_ws');
70
71		if(!isset($this->session->data['order_id'])) {
72			return false;
73		}
74
75		$order_info = $this->model_checkout_order->getOrder($this->session->data['order_id']);
76
77		if ($order_info) {
78			if ($this->config->get('payment_securetrading_ws_3d_secure')) {
79				$requestblock_xml = new SimpleXMLElement('<requestblock></requestblock>');
80				$requestblock_xml->addAttribute('version', '3.67');
81				$requestblock_xml->addChild('alias', $this->config->get('payment_securetrading_ws_username'));
82
83				$request_node = $requestblock_xml->addChild('request');
84				$request_node->addAttribute('type', 'THREEDQUERY');
85
86				$merchant_node = $request_node->addChild('merchant');
87				$merchant_node->addChild('orderreference', $order_info['order_id']);
88				$merchant_node->addChild('termurl', $this->url->link('extension/payment/securetrading_ws/threedreturn', '', true));
89
90				$settlement_node = $request_node->addChild('settlement');
91				$settlement_date = date('Y-m-d', strtotime(date('Y-m-d') . ' +' . $this->config->get('payment_securetrading_ws_settle_due_date') . ' days'));
92				$settlement_node->addChild('settleduedate', $settlement_date);
93				$settlement_node->addChild('settlestatus', $this->config->get('payment_securetrading_ws_settle_status'));
94
95				$customer_node = $request_node->addChild('customer');
96				$customer_node->addChild('useragent', $order_info['user_agent']);
97				$customer_node->addChild('accept', $this->request->server['HTTP_ACCEPT']);
98
99				$billing_node = $request_node->addChild('billing');
100				$amount_node = $billing_node->addChild('amount', str_replace('.', '', $this->model_extension_payment_securetrading_ws->format($order_info['total'], $order_info['currency_code'], $order_info['currency_value'])));
101				$amount_node->addAttribute('currencycode', $order_info['currency_code']);
102
103				$billing_node->addChild('premise', $order_info['payment_address_1']);
104				$billing_node->addChild('postcode', $order_info['payment_postcode']);
105
106				$name_node = $billing_node->addChild('name');
107				$name_node->addChild('first', $order_info['payment_firstname']);
108				$name_node->addChild('last', $order_info['payment_lastname']);
109
110				$payment_node = $billing_node->addChild('payment');
111				$payment_node->addAttribute('type', $this->request->post['type']);
112				$payment_node->addChild('pan', $this->request->post['number']);
113				$payment_node->addChild('expirydate', $this->request->post['expire_month'] . '/' . $this->request->post['expire_year']);
114				$payment_node->addChild('securitycode', $this->request->post['cvv2']);
115
116				$operation_node = $request_node->addChild('operation');
117				$operation_node->addChild('sitereference', $this->config->get('payment_securetrading_ws_site_reference'));
118				$operation_node->addChild('accounttypedescription', 'ECOM');
119
120				$response = $this->model_extension_payment_securetrading_ws->call($requestblock_xml->asXML());
121
122				if ($response !== false) {
123					$response_xml = simplexml_load_string($response);
124
125					if ($response_xml->response['type'] == 'THREEDQUERY') {
126						$error_code = (int)$response_xml->response->error->code;
127
128						if ($error_code == 0) {
129							$enrolled = (string)$response_xml->response->threedsecure->enrolled;
130
131							if ($enrolled == 'Y') {
132								$acs_url = (string)$response_xml->response->threedsecure->acsurl;
133								$md = (string)$response_xml->response->threedsecure->md;
134								$pareq = (string)$response_xml->response->threedsecure->pareq;
135
136								$this->model_extension_payment_securetrading_ws->addMd($order_info['order_id'], $md);
137
138								$json['status'] = 1;
139								$json['acs_url'] = $acs_url;
140								$json['md'] = $md;
141								$json['pareq'] = $pareq;
142								$json['term_url'] = $this->url->link('extension/payment/securetrading_ws/threedreturn', '', true);
143							} else {
144								$requestblock_xml = new SimpleXMLElement('<requestblock></requestblock>');
145								$requestblock_xml->addAttribute('version', '3.67');
146								$requestblock_xml->addChild('alias', $this->config->get('payment_securetrading_ws_username'));
147
148								$request_node = $requestblock_xml->addChild('request');
149								$request_node->addAttribute('type', 'AUTH');
150
151								$request_node->addChild('merchant')->addChild('orderreference', $order_info['order_id']);
152
153								$operation_node = $request_node->addChild('operation');
154								$operation_node->addChild('parenttransactionreference', (string)$response_xml->response->transactionreference);
155								$operation_node->addChild('sitereference', $this->config->get('payment_securetrading_ws_site_reference'));
156
157								$response = $this->model_extension_payment_securetrading_ws->call($requestblock_xml->asXML());
158
159								$json = $this->processAuthResponse($response, $order_info['order_id']);
160							}
161						} else {
162							$json['message'] = $this->language->get('text_transaction_declined');
163							$json['status'] = 0;
164						}
165					} else {
166						$json['message'] = $this->language->get('text_transaction_failed');
167						$json['status'] = 0;
168					}
169				} else {
170					$json['message'] = $this->language->get('text_connection_error');
171					$json['status'] = 0;
172				}
173			} else {
174				$country = $this->model_localisation_country->getCountry($order_info['payment_country_id']);
175
176				$json = array();
177
178				$requestblock_xml = new SimpleXMLElement('<requestblock></requestblock>');
179				$requestblock_xml->addAttribute('version', '3.67');
180				$requestblock_xml->addChild('alias', $this->config->get('payment_securetrading_ws_username'));
181
182				$request_node = $requestblock_xml->addChild('request');
183				$request_node->addAttribute('type', 'AUTH');
184				$operation_node = $request_node->addChild('operation');
185				$operation_node->addChild('sitereference', $this->config->get('payment_securetrading_ws_site_reference'));
186				$operation_node->addChild('accounttypedescription', 'ECOM');
187
188				$merchant_node = $request_node->addChild('merchant');
189				$merchant_node->addChild('orderreference', $order_info['order_id']);
190
191				$settlement_node = $request_node->addChild('settlement');
192				$settlement_date = date('Y-m-d', strtotime(date('Y-m-d') . ' +' . $this->config->get('payment_securetrading_ws_settle_due_date') . ' days'));
193				$settlement_node->addChild('settleduedate', $settlement_date);
194				$settlement_node->addChild('settlestatus', $this->config->get('payment_securetrading_ws_settle_status'));
195
196				$billing_node = $request_node->addChild('billing');
197				$billing_node->addChild('premise', $order_info['payment_address_1']);
198				$billing_node->addChild('street', $order_info['payment_address_2']);
199				$billing_node->addChild('town', $order_info['payment_city']);
200				$billing_node->addChild('county', $order_info['payment_zone']);
201				$billing_node->addChild('country', $country['iso_code_2']);
202				$billing_node->addChild('postcode', $order_info['payment_postcode']);
203				$billing_node->addChild('email', $order_info['email']);
204				$name_node = $billing_node->addChild('name');
205
206				$name_node->addChild('first', $order_info['payment_firstname']);
207				$name_node->addChild('last', $order_info['payment_lastname']);
208
209				$amount_node = $billing_node->addChild('amount', str_replace('.', '', $this->model_extension_payment_securetrading_ws->format($order_info['total'], $order_info['currency_code'], $order_info['currency_value'])));
210				$amount_node->addAttribute('currencycode', $order_info['currency_code']);
211
212				$payment_node = $billing_node->addChild('payment');
213				$payment_node->addAttribute('type', $this->request->post['type']);
214				$payment_node->addChild('pan', $this->request->post['number']);
215				$payment_node->addChild('expirydate', $this->request->post['expire_month'] . '/' . $this->request->post['expire_year']);
216				$payment_node->addChild('securitycode', $this->request->post['cvv2']);
217
218				$response = $this->model_extension_payment_securetrading_ws->call($requestblock_xml->asXML());
219
220				$json = $this->processAuthResponse($response, $order_info['order_id']);
221			}
222			$this->response->setOutput(json_encode($json));
223		}
224	}
225
226	public function threedreturn() {
227		$this->load->model('checkout/order');
228		$this->load->model('extension/payment/securetrading_ws');
229		$this->load->language('extension/payment/securetrading_ws');
230
231		// Using unmodified $_POST to access values as per Secure Trading's requirements
232		if (isset($_POST['PaRes']) && !empty($_POST['PaRes']) && isset($_POST['MD']) && !empty($_POST['MD'])) {
233			$md = $_POST['MD'];
234			$pares = $_POST['PaRes'];
235
236			$order_id = $this->model_extension_payment_securetrading_ws->getOrderId($md);
237
238			if ($order_id) {
239				$requestblock_xml = new SimpleXMLElement('<requestblock></requestblock>');
240				$requestblock_xml->addAttribute('version', '3.67');
241				$requestblock_xml->addChild('alias', $this->config->get('payment_securetrading_ws_username'));
242
243				$request_node = $requestblock_xml->addChild('request');
244				$request_node->addAttribute('type', 'AUTH');
245
246				$request_node->addChild('merchant')->addChild('orderreference', $order_id);
247
248				$operation_node = $request_node->addChild('operation');
249				$operation_node->addChild('md', $md);
250				$operation_node->addChild('pares', $pares);
251
252				$response = $this->model_extension_payment_securetrading_ws->call($requestblock_xml->asXML());
253
254				if ($response) {
255					$response_xml = simplexml_load_string($response);
256
257					$error_code = (int)$response_xml->response->error->code;
258
259					if ($error_code == 0) {
260						$postcode_status = (int)$response_xml->response->security->postcode;
261						$security_code_status = (int)$response_xml->response->security->securitycode;
262						$address_status = (int)$response_xml->response->security->address;
263						$authcode = (string)$response_xml->response->authcode;
264						$threed_status = (string)$response_xml->response->threedsecure->status;
265
266						$status_code_mapping = array(
267							0 => $this->language->get('text_not_given'),
268							1 => $this->language->get('text_not_checked'),
269							2 => $this->language->get('text_match'),
270							4 => $this->language->get('text_not_match'),
271						);
272
273						$threed_status_mapping = array(
274							'Y' => $this->language->get('text_authenticated'),
275							'N' => $this->language->get('text_not_authenticated'),
276							'A' => $this->language->get('text_authentication_not_completed'),
277							'U' => $this->language->get('text_unable_to_perform'),
278						);
279
280						$message = sprintf($this->language->get('text_auth_code'), $authcode) . "\n";
281						$message .= sprintf($this->language->get('text_postcode_check'), $status_code_mapping[$postcode_status]) . "\n";
282						$message .= sprintf($this->language->get('text_security_code_check'), $status_code_mapping[$security_code_status]) . "\n";
283						$message .= sprintf($this->language->get('text_address_check'), $status_code_mapping[$address_status]) . "\n";
284						$message .= sprintf($this->language->get('text_3d_secure_check'), $threed_status_mapping[$threed_status]) . "\n";
285
286						$transaction_reference = (string)$response_xml->response->transactionreference;
287						$this->model_extension_payment_securetrading_ws->updateReference($order_id, $transaction_reference);
288
289						$this->model_extension_payment_securetrading_ws->confirmOrder($order_id, $this->config->get('payment_securetrading_ws_order_status_id'));
290						$this->model_extension_payment_securetrading_ws->updateOrder($order_id, $this->config->get('payment_securetrading_ws_order_status_id'), $message);
291
292						$this->response->redirect($this->url->link('checkout/success', '', true));
293					} else {
294						$this->model_extension_payment_securetrading_ws->updateOrder($order_id, $this->config->get('payment_securetrading_ws_declined_order_status_id'));
295
296						$this->session->data['error'] = $this->language->get('text_transaction_declined');
297						$this->response->redirect($this->url->link('checkout/checkout', '', true));
298					}
299				} else {
300					$this->session->data['error'] = $this->language->get('error_failure');
301					$this->response->redirect($this->url->link('checkout/checkout', '', true));
302				}
303			} else {
304				$this->session->data['error'] = $this->language->get('error_failure');
305				$this->response->redirect($this->url->link('checkout/checkout', '', true));
306			}
307		} else {
308			$this->session->data['error'] = $this->language->get('error_failure');
309			$this->response->redirect($this->url->link('checkout/checkout', '', true));
310		}
311	}
312
313	private function processAuthResponse($response, $order_id) {
314		$json = array();
315
316		if ($response !== false) {
317			$response_xml = simplexml_load_string($response);
318
319			if ($response_xml->response['type'] == 'AUTH') {
320				$error_code = (int)$response_xml->response->error->code;
321
322				if ($error_code == 0) {
323					$postcode_status = (int)$response_xml->response->security->postcode;
324					$security_code_status = (int)$response_xml->response->security->securitycode;
325					$address_status = (int)$response_xml->response->security->address;
326					$authcode = (string)$response_xml->response->authcode;
327
328					$status_code_mapping = array(
329						0 => $this->language->get('text_not_given'),
330						1 => $this->language->get('text_not_checked'),
331						2 => $this->language->get('text_match'),
332						4 => $this->language->get('text_not_match'),
333					);
334
335					$message = sprintf($this->language->get('text_auth_code'), $authcode) . "\n";
336					$message .= sprintf($this->language->get('text_postcode_check'), $status_code_mapping[$postcode_status]) . "\n";
337					$message .= sprintf($this->language->get('text_security_code_check'), $status_code_mapping[$security_code_status]) . "\n";
338					$message .= sprintf($this->language->get('text_address_check'), $status_code_mapping[$address_status]) . "\n";
339
340					$transaction_reference = (string)$response_xml->response->transactionreference;
341					$this->model_extension_payment_securetrading_ws->updateReference($order_id, $transaction_reference);
342
343					$this->model_extension_payment_securetrading_ws->confirmOrder($order_id, $this->config->get('payment_securetrading_ws_order_status_id'));
344					$this->model_extension_payment_securetrading_ws->updateOrder($order_id, $this->config->get('payment_securetrading_ws_order_status_id'), $message);
345
346					$json['redirect'] = $this->url->link('checkout/success');
347					$json['status'] = 1;
348				} else {
349					$this->model_extension_payment_securetrading_ws->updateOrder($order_id, $this->config->get('payment_securetrading_ws_declined_order_status_id'));
350
351					$json['message'] = $this->language->get('text_transaction_declined');
352					$json['status'] = 0;
353				}
354			} else {
355				$this->model_extension_payment_securetrading_ws->updateOrder($order_id, $this->config->get('payment_securetrading_ws_failed_order_status_id'));
356
357				$json['message'] = $this->language->get('text_transaction_failed');
358				$json['status'] = 0;
359			}
360		} else {
361			$json['message'] = $this->language->get('text_connection_error');
362			$json['status'] = 0;
363		}
364
365		return $json;
366	}
367}
368